agentic-aqua 0.3.0__py3-none-any.whl
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.
- agentic_aqua-0.3.0.dist-info/METADATA +327 -0
- agentic_aqua-0.3.0.dist-info/RECORD +25 -0
- agentic_aqua-0.3.0.dist-info/WHEEL +4 -0
- agentic_aqua-0.3.0.dist-info/entry_points.txt +3 -0
- agentic_aqua-0.3.0.dist-info/licenses/LICENSE +21 -0
- aqua/__init__.py +3 -0
- aqua/ankara.py +90 -0
- aqua/assets.py +92 -0
- aqua/bitcoin.py +387 -0
- aqua/boltz.py +165 -0
- aqua/cli/__init__.py +5 -0
- aqua/cli/btc.py +81 -0
- aqua/cli/commands.py +30 -0
- aqua/cli/lightning.py +87 -0
- aqua/cli/liquid.py +201 -0
- aqua/cli/main.py +45 -0
- aqua/cli/output.py +68 -0
- aqua/cli/password.py +49 -0
- aqua/cli/serve.py +13 -0
- aqua/cli/wallet.py +150 -0
- aqua/lightning.py +387 -0
- aqua/server.py +1175 -0
- aqua/storage.py +342 -0
- aqua/tools.py +740 -0
- aqua/wallet.py +362 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentic-aqua
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Agentic AQUA — MCP server for Liquid Network and Bitcoin wallet operations
|
|
5
|
+
Project-URL: Homepage, https://github.com/jan3dev/agentic-aqua
|
|
6
|
+
Project-URL: Repository, https://github.com/jan3dev/agentic-aqua
|
|
7
|
+
Project-URL: Documentation, https://github.com/jan3dev/agentic-aqua#readme
|
|
8
|
+
Author-email: Andy <andy@example.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai,bitcoin,blockstream,liquid,lwk,mcp,wallet
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.13
|
|
18
|
+
Requires-Dist: bdkpython>=2.2.0
|
|
19
|
+
Requires-Dist: click>=8.1
|
|
20
|
+
Requires-Dist: coincurve>=21.0.0
|
|
21
|
+
Requires-Dist: cryptography>=42.0.0
|
|
22
|
+
Requires-Dist: lwk>=0.8.0
|
|
23
|
+
Requires-Dist: mcp>=1.0.0
|
|
24
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: black>=24.0.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.2.0; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# Agentic AQUA
|
|
34
|
+
|
|
35
|
+
MCP server and CLI for managing **Liquid Network** and **Bitcoin** wallets through AI assistants like Claude. One mnemonic backs both networks (unified wallet). Also can operates on Lightning network via Boltz swaps.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **Generate & Import** - Create new wallets or import existing mnemonics
|
|
40
|
+
- **Unified Wallet** - One mnemonic for Liquid and Bitcoin; `unified_balance` shows both
|
|
41
|
+
- **Bitcoin (onchain)** - BIP84 wallets, balance and send via `btc_*` tools (BDK)
|
|
42
|
+
- **Watch-Only** - Import CT descriptors for balance monitoring
|
|
43
|
+
- **Send & Receive** - Full transaction support (L-BTC, BTC, and Liquid assets)
|
|
44
|
+
- **Lightning** - Send and receive via Lightning using L-BTC (via Boltz & Ankara)
|
|
45
|
+
- **Assets** - Native support for L-BTC, USDT, and all Liquid assets
|
|
46
|
+
- **Secure** - Encrypted storage, no remote servers for keys
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
> **Quickest way:** just ask your AI agent directly:
|
|
51
|
+
>
|
|
52
|
+
> ```
|
|
53
|
+
> Install this MCP server: https://github.com/jan3dev/agentic-aqua
|
|
54
|
+
> ```
|
|
55
|
+
|
|
56
|
+
### Recommended (uvx)
|
|
57
|
+
|
|
58
|
+
If you don't have `uvx` installed:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# macOS/Linux
|
|
62
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
63
|
+
|
|
64
|
+
# Windows
|
|
65
|
+
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Configure Claude Desktop (`~/.claude/claude_desktop_config.json`):
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"mcpServers": {
|
|
73
|
+
"agentic-aqua": {
|
|
74
|
+
"command": "/full/path/to/uvx",
|
|
75
|
+
"args": ["agentic-aqua"]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Find the full path to `uvx` with:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
which uvx
|
|
85
|
+
# Example: /Users/yourname/.local/bin/uvx
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Restart Claude Desktop and you're ready to use Bitcoin and Liquid wallets.
|
|
89
|
+
|
|
90
|
+
### For Developers
|
|
91
|
+
|
|
92
|
+
Clone and install from source:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/jan3dev/agentic-aqua.git
|
|
96
|
+
cd agentic-aqua
|
|
97
|
+
uv sync
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Configure Claude Desktop using the full path to `uv` (find with `which uv`):
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"mcpServers": {
|
|
105
|
+
"agentic-aqua": {
|
|
106
|
+
"command": "/full/path/to/uv",
|
|
107
|
+
"args": ["run", "--directory", "/absolute/path/to/agentic-aqua", "python", "-m", "aqua.server"]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Quick Start
|
|
114
|
+
|
|
115
|
+
Once connected, you can ask Claude to:
|
|
116
|
+
|
|
117
|
+
- "Create a new wallet" (creates both Bitcoin and Liquid wallets from one mnemonic)
|
|
118
|
+
- "Show my balance" / "What's my Bitcoin balance?"
|
|
119
|
+
- "Generate a receive address" (Liquid or Bitcoin)
|
|
120
|
+
- "Send 10,000 sats to bc1..." / "Send 0.001 L-BTC to lq1..."
|
|
121
|
+
- "Pay this Lightning invoice: lnbc..."
|
|
122
|
+
- "Receive 50,000 sats via Lightning"
|
|
123
|
+
- "Delete my wallet"
|
|
124
|
+
|
|
125
|
+
## Available Tools
|
|
126
|
+
|
|
127
|
+
**Wallet Management**
|
|
128
|
+
|
|
129
|
+
| Tool | Description |
|
|
130
|
+
|------|-------------|
|
|
131
|
+
| `lw_generate_mnemonic` | Generate new BIP39 mnemonic |
|
|
132
|
+
| `lw_import_mnemonic` | Import wallet from mnemonic (also creates Bitcoin wallet) |
|
|
133
|
+
| `lw_import_descriptor` | Import watch-only wallet from CT descriptor |
|
|
134
|
+
| `lw_export_descriptor` | Export CT descriptor for watch-only use |
|
|
135
|
+
| `lw_list_wallets` | List all wallets |
|
|
136
|
+
| `delete_wallet` | Delete a wallet and all its cached data |
|
|
137
|
+
|
|
138
|
+
**Liquid (lw_*)**
|
|
139
|
+
|
|
140
|
+
| Tool | Description |
|
|
141
|
+
|------|-------------|
|
|
142
|
+
| `lw_balance` | Get wallet balances (all assets) |
|
|
143
|
+
| `lw_address` | Generate Liquid receive address (lq1...) |
|
|
144
|
+
| `lw_send` | Send L-BTC |
|
|
145
|
+
| `lw_send_asset` | Send any Liquid asset (USDT, etc.) |
|
|
146
|
+
| `lw_transactions` | Transaction history |
|
|
147
|
+
| `lw_tx_status` | Get transaction status (txid or explorer URL) |
|
|
148
|
+
|
|
149
|
+
**Bitcoin (btc_*)**
|
|
150
|
+
|
|
151
|
+
| Tool | Description |
|
|
152
|
+
|------|-------------|
|
|
153
|
+
| `btc_balance` | Get Bitcoin balance (sats) |
|
|
154
|
+
| `btc_address` | Generate Bitcoin receive address (bc1...) |
|
|
155
|
+
| `btc_transactions` | Bitcoin transaction history |
|
|
156
|
+
| `btc_send` | Send BTC |
|
|
157
|
+
|
|
158
|
+
**Unified**
|
|
159
|
+
|
|
160
|
+
| Tool | Description |
|
|
161
|
+
|------|-------------|
|
|
162
|
+
| `unified_balance` | Get balance for both Bitcoin and Liquid |
|
|
163
|
+
|
|
164
|
+
**Lightning**
|
|
165
|
+
|
|
166
|
+
| Tool | Description |
|
|
167
|
+
|------|-------------|
|
|
168
|
+
| `lightning_receive` | Generate a Lightning invoice to receive L-BTC (100–25,000,000 sats) |
|
|
169
|
+
| `lightning_send` | Pay a Lightning invoice using L-BTC via Boltz (~0.1% fee) |
|
|
170
|
+
| `lightning_transaction_status` | Check status of a Lightning swap (send or receive) |
|
|
171
|
+
|
|
172
|
+
## CLI
|
|
173
|
+
|
|
174
|
+
Agentic AQUA also ships with a Click-based CLI (`aqua`) for direct, scriptable wallet operations. It exposes the same operations as the MCP tools.
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# Discover commands
|
|
178
|
+
aqua --help
|
|
179
|
+
aqua wallet --help
|
|
180
|
+
aqua btc --help
|
|
181
|
+
aqua liquid --help
|
|
182
|
+
aqua lightning --help
|
|
183
|
+
|
|
184
|
+
# Wallet management
|
|
185
|
+
aqua wallet generate-mnemonic
|
|
186
|
+
aqua wallet import-mnemonic --wallet-name default --network mainnet
|
|
187
|
+
aqua wallet list
|
|
188
|
+
aqua wallet export-descriptor --wallet-name default
|
|
189
|
+
aqua wallet delete --wallet-name old
|
|
190
|
+
|
|
191
|
+
# Balances
|
|
192
|
+
aqua balance # unified (BTC + Liquid)
|
|
193
|
+
aqua btc balance --wallet-name default
|
|
194
|
+
aqua liquid balance --wallet-name default
|
|
195
|
+
|
|
196
|
+
# Receive addresses
|
|
197
|
+
aqua btc address
|
|
198
|
+
aqua liquid address
|
|
199
|
+
|
|
200
|
+
# Send (--wallet-name is required for on-chain sends)
|
|
201
|
+
aqua btc send --wallet-name default --address bc1... --amount 10000
|
|
202
|
+
aqua liquid send --wallet-name default --address lq1... --amount 50000
|
|
203
|
+
aqua liquid send-asset --wallet-name default --address lq1... --amount 1000000 --asset-id <asset_id>
|
|
204
|
+
# (or use --asset-ticker USDt instead of --asset-id)
|
|
205
|
+
|
|
206
|
+
# Transaction history & status
|
|
207
|
+
aqua btc transactions
|
|
208
|
+
aqua liquid transactions
|
|
209
|
+
aqua liquid tx-status --tx <txid|explorer_url>
|
|
210
|
+
|
|
211
|
+
# Lightning (L-BTC via Boltz / Ankara)
|
|
212
|
+
aqua lightning receive --amount 50000
|
|
213
|
+
aqua lightning send --invoice lnbc...
|
|
214
|
+
aqua lightning status --swap-id <id>
|
|
215
|
+
|
|
216
|
+
# Run as MCP stdio server
|
|
217
|
+
aqua serve # recommended
|
|
218
|
+
aqua-mcp # direct MCP entrypoint
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Output defaults to a human-readable table on the terminal and JSON when piped. Force a format with `--format json` or `--format pretty`.
|
|
222
|
+
|
|
223
|
+
### Loading mnemonics safely (env vars from a text file)
|
|
224
|
+
|
|
225
|
+
Avoid pasting mnemonics into shell prompts or chat with an AI agent — both shell history and agent transcripts may persist them. The recommended workflow is to keep secrets in a local text file with restricted permissions and load them as environment variables.
|
|
226
|
+
|
|
227
|
+
1. Create `~/.aqua/secrets.env` (or any path you prefer) and lock it down:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
mkdir -p ~/.aqua
|
|
231
|
+
cat > ~/.aqua/secrets.env <<'EOF'
|
|
232
|
+
AQUA_MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
233
|
+
AQUA_PASSWORD="Wild-red-dolphin-386"
|
|
234
|
+
EOF
|
|
235
|
+
chmod 600 ~/.aqua/secrets.env
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
2. Source it before running CLI commands and clear it afterwards:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
set -a; . ~/.aqua/secrets.env; set +a
|
|
242
|
+
aqua-cli wallet import-mnemonic --wallet-name default --network mainnet
|
|
243
|
+
unset AQUA_MNEMONIC AQUA_PASSWORD
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
`aqua-cli` also auto-loads a `.env` file from the project root via `python-dotenv` if you prefer a per-project file.
|
|
247
|
+
|
|
248
|
+
The CLI honors these variables out of the box:
|
|
249
|
+
|
|
250
|
+
| Variable | Used by |
|
|
251
|
+
|----------|---------|
|
|
252
|
+
| `AQUA_MNEMONIC` | `wallet import-mnemonic` |
|
|
253
|
+
| `AQUA_PASSWORD` | `wallet import-mnemonic`, `btc send`, `liquid send`, `liquid send-asset`, `lightning send`, `lightning receive` |
|
|
254
|
+
| `AQUA_<OPTION>` | Any CLI option (Click `auto_envvar_prefix="AQUA"`) — e.g. `AQUA_WALLET_NAME=default` |
|
|
255
|
+
|
|
256
|
+
If you would rather pipe secrets from a password manager, every secret-bearing command also accepts `--mnemonic-stdin` / `--password-stdin`:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
pass show crypto/aqua-mnemonic | aqua-cli wallet import-mnemonic --mnemonic-stdin
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Tips:
|
|
263
|
+
- Never commit `.env` or `secrets.env` files (the project's `.gitignore` already excludes them).
|
|
264
|
+
- Prefer `set -a; . file; set +a` over `export $(cat file)` — the former tolerates spaces and quotes inside values.
|
|
265
|
+
- After importing a wallet, the mnemonic is no longer needed for day-to-day operations; only `AQUA_PASSWORD` is used to sign transactions.
|
|
266
|
+
|
|
267
|
+
## Configuration
|
|
268
|
+
|
|
269
|
+
Default config location: `~/.aqua/config.json`
|
|
270
|
+
|
|
271
|
+
> **Migrating from `aqua-mcp`?** The config dir moved from `~/.aqua-mcp` to `~/.aqua`. There is no automatic migration. To carry over your wallets, run once:
|
|
272
|
+
>
|
|
273
|
+
> ```bash
|
|
274
|
+
> mv ~/.aqua-mcp ~/.aqua
|
|
275
|
+
> ```
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
{
|
|
279
|
+
"network": "mainnet",
|
|
280
|
+
"default_wallet": "default",
|
|
281
|
+
"electrum_url": null,
|
|
282
|
+
"auto_sync": true
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Security
|
|
287
|
+
|
|
288
|
+
Mnemonics are encrypted at rest using a password (PBKDF2 + Fernet). Without a password, the mnemonic is stored base64-encoded only — use a password for real funds. **Note:** this password is NOT a BIP39 passphrase; the derived Liquid/Bitcoin keys depend solely on the mnemonic, so the same mnemonic restores identical descriptors in any BIP39-compliant wallet (AQUA, Blockstream Green, Jade, etc.).
|
|
289
|
+
|
|
290
|
+
For maximum security you can:
|
|
291
|
+
1. Generate wallet on an air-gapped device
|
|
292
|
+
2. Export the CT descriptor
|
|
293
|
+
3. Import as watch-only on your daily machine
|
|
294
|
+
|
|
295
|
+
All private key operations happen locally. Only blockchain sync uses Blockstream's public servers.
|
|
296
|
+
|
|
297
|
+
## Development
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
# Install with dev dependencies
|
|
301
|
+
uv sync --all-extras
|
|
302
|
+
|
|
303
|
+
# Run tests
|
|
304
|
+
uv run python -m pytest tests/
|
|
305
|
+
|
|
306
|
+
# Format code
|
|
307
|
+
uv run black src/
|
|
308
|
+
uv run ruff check src/
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Architecture
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
AI Assistant ←→ MCP Server (Python) ←→ LWK (Liquid) ──→ Electrum/Esplora
|
|
315
|
+
│
|
|
316
|
+
├──→ BDK (Bitcoin) ──→ Esplora (Blockstream)
|
|
317
|
+
│
|
|
318
|
+
└──→ Boltz / Ankara ──→ Lightning
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Credits
|
|
322
|
+
|
|
323
|
+
Built with:
|
|
324
|
+
- [LWK](https://github.com/Blockstream/lwk) - Liquid Wallet Kit by Blockstream
|
|
325
|
+
- [BDK](https://github.com/bitcoindevkit/bdk-python) - Bitcoin Development Kit
|
|
326
|
+
- [MCP](https://modelcontextprotocol.io/) - Model Context Protocol
|
|
327
|
+
- [Boltz](https://boltz.exchange/) - Submarine swaps for Lightning
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
aqua/__init__.py,sha256=FjAAbyjKfcG8H4gclAuCM68qVcFKD-P5O36HclYx51o,109
|
|
2
|
+
aqua/ankara.py,sha256=AUXPzobm_LhOLlJCJjkq1jBs1e-kCN-DF1XIu0kCtSQ,2972
|
|
3
|
+
aqua/assets.py,sha256=UnN-5CZc_Bj3QyCs_dsHMmsXKh0moD10DZjj4GNo32s,3138
|
|
4
|
+
aqua/bitcoin.py,sha256=uqiicA4Sc-b-oi5Gwl6z3KPp-eZg12xjNm-WRrHAQ4M,13836
|
|
5
|
+
aqua/boltz.py,sha256=oomJVqYjTPWAqKTaT-Lpx5gTHoQ6par5Mb6RBw3aa68,5259
|
|
6
|
+
aqua/lightning.py,sha256=KCxR14EEr1z5On7xo6dbpIdi5r-Mv88STVtHtHU93e0,14115
|
|
7
|
+
aqua/server.py,sha256=pPmFU2tjnYxNeIw-tjFPRh89xnLGi1Gv9RKJQFEmCBA,42587
|
|
8
|
+
aqua/storage.py,sha256=yGAcYQKPK79vRfnnGGh12-xWaSZdNoTy330ePBQOazc,12238
|
|
9
|
+
aqua/tools.py,sha256=GSFweNv8V3nta6Vf5k0tGm0QWppZZt2RBaWsp6Q6IKw,22133
|
|
10
|
+
aqua/wallet.py,sha256=nVUjRckY8V_J4qEt8H85KAK8gF8DPSZEvepwKjiJ_ZU,11409
|
|
11
|
+
aqua/cli/__init__.py,sha256=iDaGtdJuhg5j7eV4H_EARyjSIUNWM-uWx0ZpcCE9XUU,90
|
|
12
|
+
aqua/cli/btc.py,sha256=yMSkiR2MprUnnCRBhCzDFupPLzpsfh5EmcIehKffWwA,2605
|
|
13
|
+
aqua/cli/commands.py,sha256=CSzabNlYzXGJqzc8W1lJJNlPY4VtzXOwP1An6r51ts8,857
|
|
14
|
+
aqua/cli/lightning.py,sha256=dMJZ5JkPtSEMMcH8Idm-uYIpkeJEIQygYI_j-JOC-xc,2641
|
|
15
|
+
aqua/cli/liquid.py,sha256=Zs32RdDnN8zQ8FpYfNwBhQwhqT0DfS5blL_8BpAcKtE,6072
|
|
16
|
+
aqua/cli/main.py,sha256=pP1pbJRUwtkO3_oE9vza7uBWb0BZ2fUvZnFfQGTkwt0,1360
|
|
17
|
+
aqua/cli/output.py,sha256=FWa-5SUsxkJ8or7GqMDx1BZEH0mL64Y_SN_dC20kU58,2167
|
|
18
|
+
aqua/cli/password.py,sha256=JiSZAhqEUHuoaRzA-_TY3MT7A1l3FujZnm46SDl00S4,1556
|
|
19
|
+
aqua/cli/serve.py,sha256=v6dX5D5gg61orH_1hOHqo7EGVuieC7a3G1QR06LIvFI,261
|
|
20
|
+
aqua/cli/wallet.py,sha256=xA4MwyCt9ynABBTgFxORThZktc1YgKTJGIsic1_8hnA,4478
|
|
21
|
+
agentic_aqua-0.3.0.dist-info/METADATA,sha256=pneU99x5bYMMFRyexJZG5MkRQ-0E2PdIYwNDqECYIWw,10694
|
|
22
|
+
agentic_aqua-0.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
23
|
+
agentic_aqua-0.3.0.dist-info/entry_points.txt,sha256=daLwm0HZ381CB4DGSxTYMOAd6LEeVjXOds9jeRk8Ntg,71
|
|
24
|
+
agentic_aqua-0.3.0.dist-info/licenses/LICENSE,sha256=ESYyLizI0WWtxMeS7rGVcX3ivMezm-HOd5WdeOh-9oU,1056
|
|
25
|
+
agentic_aqua-0.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aqua/__init__.py
ADDED
aqua/ankara.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Ankara backend integration for Lightning → L-BTC swaps."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import urllib.error
|
|
6
|
+
import urllib.request
|
|
7
|
+
from dataclasses import asdict, dataclass
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
# API URL with environment variable override
|
|
11
|
+
ANKARA_API_URL = os.environ.get("ANKARA_API_URL", "https://ankara.aquabtc.com")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class AnkaraSwapInfo:
|
|
16
|
+
"""Holds all data for an active/completed Ankara Lightning swap."""
|
|
17
|
+
|
|
18
|
+
swap_id: str
|
|
19
|
+
boltz_swap_id: str
|
|
20
|
+
invoice: str
|
|
21
|
+
address: str
|
|
22
|
+
amount: int
|
|
23
|
+
wallet_name: str
|
|
24
|
+
status: str # "pending" | "settled" | "failed"
|
|
25
|
+
created_at: str
|
|
26
|
+
preimage: Optional[str] = None
|
|
27
|
+
|
|
28
|
+
def to_dict(self) -> dict:
|
|
29
|
+
return asdict(self)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def from_dict(cls, data: dict) -> "AnkaraSwapInfo":
|
|
33
|
+
return cls(**data)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class AnkaraClient:
|
|
37
|
+
"""HTTP client for Ankara backend API."""
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self.base_url = ANKARA_API_URL
|
|
41
|
+
|
|
42
|
+
def _api_request(self, method: str, path: str, body: dict | None = None) -> dict:
|
|
43
|
+
"""Make HTTP request to Ankara API."""
|
|
44
|
+
url = f"{self.base_url}{path}"
|
|
45
|
+
data = json.dumps(body).encode() if body else None
|
|
46
|
+
req = urllib.request.Request(
|
|
47
|
+
url,
|
|
48
|
+
data=data,
|
|
49
|
+
method=method,
|
|
50
|
+
headers={
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
"User-Agent": "agentic-aqua",
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
try:
|
|
56
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
57
|
+
return json.loads(resp.read().decode())
|
|
58
|
+
except urllib.error.HTTPError as e:
|
|
59
|
+
# Try to extract error message from response body
|
|
60
|
+
detail = ""
|
|
61
|
+
try:
|
|
62
|
+
err_body = json.loads(e.read().decode())
|
|
63
|
+
detail = err_body.get("error", err_body.get("message", ""))
|
|
64
|
+
except Exception:
|
|
65
|
+
pass
|
|
66
|
+
msg = f"Ankara API error ({e.code} {method} {path})"
|
|
67
|
+
if detail:
|
|
68
|
+
msg += f": {detail}"
|
|
69
|
+
raise RuntimeError(msg) from e
|
|
70
|
+
except urllib.error.URLError as e:
|
|
71
|
+
raise RuntimeError(f"Ankara API unreachable ({method} {path}): {e.reason}") from e
|
|
72
|
+
|
|
73
|
+
def create_swap(self, amount: int, address: str) -> dict:
|
|
74
|
+
"""POST /api/v1/lightning/swaps/create/ - create a new swap."""
|
|
75
|
+
return self._api_request(
|
|
76
|
+
"POST",
|
|
77
|
+
"/api/v1/lightning/swaps/create/",
|
|
78
|
+
{
|
|
79
|
+
"amount": amount,
|
|
80
|
+
"address": address,
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def claim_swap(self, swap_id: str) -> dict:
|
|
85
|
+
"""POST /api/v1/lightning/swaps/{swap_id}/claim/ - claim a swap."""
|
|
86
|
+
return self._api_request("POST", f"/api/v1/lightning/swaps/{swap_id}/claim/")
|
|
87
|
+
|
|
88
|
+
def verify_swap(self, swap_id: str) -> dict:
|
|
89
|
+
"""GET /api/v1/lightning/lnurlp/verify/{swap_id} - verify swap status."""
|
|
90
|
+
return self._api_request("GET", f"/api/v1/lightning/lnurlp/verify/{swap_id}")
|
aqua/assets.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Known Liquid Network asset registry."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class AssetInfo:
|
|
9
|
+
"""Metadata for a known Liquid asset."""
|
|
10
|
+
|
|
11
|
+
asset_id: str
|
|
12
|
+
name: str
|
|
13
|
+
ticker: str
|
|
14
|
+
logo: str
|
|
15
|
+
precision: int # Number of decimal places (e.g. 8 means divide by 10^8)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Mainnet known assets
|
|
19
|
+
MAINNET_ASSETS: dict[str, AssetInfo] = {
|
|
20
|
+
info.asset_id: info
|
|
21
|
+
for info in [
|
|
22
|
+
AssetInfo(
|
|
23
|
+
asset_id="6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
|
|
24
|
+
name="Liquid Bitcoin",
|
|
25
|
+
ticker="L-BTC",
|
|
26
|
+
logo="https://aqua-asset-logos.s3.us-west-2.amazonaws.com/L-BTC.svg",
|
|
27
|
+
precision=8,
|
|
28
|
+
),
|
|
29
|
+
AssetInfo(
|
|
30
|
+
asset_id="ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2",
|
|
31
|
+
name="Tether USDt",
|
|
32
|
+
ticker="USDt",
|
|
33
|
+
logo="https://aqua-asset-logos.s3.us-west-2.amazonaws.com/USDt.svg",
|
|
34
|
+
precision=8,
|
|
35
|
+
),
|
|
36
|
+
AssetInfo(
|
|
37
|
+
asset_id="3438ecb49fc45c08e687de4749ed628c511e326460ea4336794e1cf02741329e",
|
|
38
|
+
name="JPY Stablecoin",
|
|
39
|
+
ticker="JPYS",
|
|
40
|
+
logo="https://aqua-asset-logos.s3.us-west-2.amazonaws.com/JPYS.svg",
|
|
41
|
+
precision=8,
|
|
42
|
+
),
|
|
43
|
+
AssetInfo(
|
|
44
|
+
asset_id="18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec",
|
|
45
|
+
name="PEGx EURx",
|
|
46
|
+
ticker="EURx",
|
|
47
|
+
logo="https://aqua-asset-logos.s3.us-west-2.amazonaws.com/EURx.svg",
|
|
48
|
+
precision=8,
|
|
49
|
+
),
|
|
50
|
+
AssetInfo(
|
|
51
|
+
asset_id="26ac924263ba547b706251635550a8649545ee5c074fe5db8d7140557baaf32e",
|
|
52
|
+
name="Mexas",
|
|
53
|
+
ticker="MEX",
|
|
54
|
+
logo="https://aqua-asset-logos.s3.us-west-2.amazonaws.com/MEX.svg",
|
|
55
|
+
precision=8,
|
|
56
|
+
),
|
|
57
|
+
AssetInfo(
|
|
58
|
+
asset_id="02f22f8d9c76ab41661a2729e4752e2c5d1a263012141b86ea98af5472df5189",
|
|
59
|
+
name="DePix",
|
|
60
|
+
ticker="DePix",
|
|
61
|
+
logo="https://aqua-asset-logos.s3.us-west-2.amazonaws.com/DePix.svg",
|
|
62
|
+
precision=8,
|
|
63
|
+
),
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Testnet known assets (policy asset only for now)
|
|
68
|
+
TESTNET_ASSETS: dict[str, AssetInfo] = {}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def lookup_asset(asset_id: str, network: str = "mainnet") -> Optional[AssetInfo]:
|
|
72
|
+
"""Look up asset metadata by ID. Returns None if unknown."""
|
|
73
|
+
registry = MAINNET_ASSETS if network == "mainnet" else TESTNET_ASSETS
|
|
74
|
+
return registry.get(asset_id)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def resolve_asset_name(asset_id: str, network: str = "mainnet") -> str:
|
|
78
|
+
"""Return ticker if known, otherwise truncated asset ID."""
|
|
79
|
+
info = lookup_asset(asset_id, network)
|
|
80
|
+
if info:
|
|
81
|
+
return info.ticker
|
|
82
|
+
return asset_id[:8] + "..."
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def lookup_asset_by_ticker(ticker: str, network: str = "mainnet") -> Optional[AssetInfo]:
|
|
86
|
+
"""Look up asset metadata by ticker (case-insensitive). Returns None if unknown."""
|
|
87
|
+
registry = MAINNET_ASSETS if network == "mainnet" else TESTNET_ASSETS
|
|
88
|
+
target = ticker.lower()
|
|
89
|
+
for info in registry.values():
|
|
90
|
+
if info.ticker.lower() == target:
|
|
91
|
+
return info
|
|
92
|
+
return None
|