cartha-cli 1.0.2__py3-none-any.whl → 1.0.3__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.
@@ -50,7 +50,7 @@ def _fallback_pool_id_to_name(pool_id: str) -> str | None:
50
50
 
51
51
  # Try to import from testnet module, fallback to default if not available
52
52
  try:
53
- from ...testnet.pool_ids import pool_id_to_name
53
+ from ..testnet.pool_ids import pool_id_to_name
54
54
  except (ImportError, ModuleNotFoundError):
55
55
  # Use fallback function
56
56
  pool_id_to_name = _fallback_pool_id_to_name
@@ -22,36 +22,16 @@ def _fallback_pool_id_to_chain_id(pool_id: str) -> int | None:
22
22
 
23
23
  # Try to import from testnet module, fallback to defaults if not available
24
24
  try:
25
- from ...testnet.pool_ids import (
25
+ from ..testnet.pool_ids import (
26
26
  list_pools,
27
27
  pool_id_to_chain_id,
28
28
  pool_id_to_vault_address,
29
29
  )
30
30
  except (ImportError, ModuleNotFoundError):
31
- # Fallback if running from different context
32
- import sys
33
- from pathlib import Path
34
-
35
- # Try adding parent directory to path
36
- testnet_dir = Path(__file__).parent.parent.parent / "testnet"
37
- if testnet_dir.exists():
38
- sys.path.insert(0, str(testnet_dir.parent))
39
- try:
40
- from testnet.pool_ids import (
41
- list_pools,
42
- pool_id_to_chain_id,
43
- pool_id_to_vault_address,
44
- )
45
- except (ImportError, ModuleNotFoundError):
46
- # Use fallback functions
47
- list_pools = _fallback_list_pools
48
- pool_id_to_vault_address = _fallback_pool_id_to_vault_address
49
- pool_id_to_chain_id = _fallback_pool_id_to_chain_id
50
- else:
51
- # Use fallback functions if testnet directory doesn't exist
52
- list_pools = _fallback_list_pools
53
- pool_id_to_vault_address = _fallback_pool_id_to_vault_address
54
- pool_id_to_chain_id = _fallback_pool_id_to_chain_id
31
+ # Use fallback functions if import failed
32
+ list_pools = _fallback_list_pools
33
+ pool_id_to_vault_address = _fallback_pool_id_to_vault_address
34
+ pool_id_to_chain_id = _fallback_pool_id_to_chain_id
55
35
 
56
36
 
57
37
  def pools(
@@ -86,7 +86,8 @@ def _fallback_vault_address_to_chain_id(vault_address: str) -> int | None:
86
86
 
87
87
  # Try to import from testnet module, fallback to defaults if not available
88
88
  try:
89
- from ...testnet.pool_ids import (
89
+ # Import from cartha_cli.testnet (works both in development and when installed)
90
+ from ..testnet.pool_ids import (
90
91
  format_pool_id,
91
92
  list_pools,
92
93
  pool_id_to_chain_id,
@@ -97,45 +98,15 @@ try:
97
98
  vault_address_to_pool_id,
98
99
  )
99
100
  except (ImportError, ModuleNotFoundError):
100
- # Fallback if running from different context
101
- import sys
102
- from pathlib import Path
103
-
104
- # Try adding parent directory to path
105
- testnet_dir = Path(__file__).parent.parent.parent / "testnet"
106
- if testnet_dir.exists():
107
- sys.path.insert(0, str(testnet_dir.parent))
108
- try:
109
- from testnet.pool_ids import (
110
- format_pool_id,
111
- list_pools,
112
- pool_id_to_chain_id,
113
- pool_id_to_name,
114
- pool_id_to_vault_address,
115
- pool_name_to_id,
116
- vault_address_to_chain_id,
117
- vault_address_to_pool_id,
118
- )
119
- except (ImportError, ModuleNotFoundError):
120
- # Use fallback functions
121
- pool_name_to_id = _fallback_pool_name_to_id
122
- pool_id_to_name = _fallback_pool_id_to_name
123
- format_pool_id = _fallback_format_pool_id
124
- list_pools = _fallback_list_pools
125
- pool_id_to_vault_address = _fallback_pool_id_to_vault_address
126
- vault_address_to_pool_id = _fallback_vault_address_to_pool_id
127
- pool_id_to_chain_id = _fallback_pool_id_to_chain_id
128
- vault_address_to_chain_id = _fallback_vault_address_to_chain_id
129
- else:
130
- # Use fallback functions if testnet directory doesn't exist
131
- pool_name_to_id = _fallback_pool_name_to_id
132
- pool_id_to_name = _fallback_pool_id_to_name
133
- format_pool_id = _fallback_format_pool_id
134
- list_pools = _fallback_list_pools
135
- pool_id_to_vault_address = _fallback_pool_id_to_vault_address
136
- vault_address_to_pool_id = _fallback_vault_address_to_pool_id
137
- pool_id_to_chain_id = _fallback_pool_id_to_chain_id
138
- vault_address_to_chain_id = _fallback_vault_address_to_chain_id
101
+ # Use fallback functions if import failed
102
+ pool_name_to_id = _fallback_pool_name_to_id
103
+ pool_id_to_name = _fallback_pool_id_to_name
104
+ format_pool_id = _fallback_format_pool_id
105
+ list_pools = _fallback_list_pools
106
+ pool_id_to_vault_address = _fallback_pool_id_to_vault_address
107
+ vault_address_to_pool_id = _fallback_vault_address_to_pool_id
108
+ pool_id_to_chain_id = _fallback_pool_id_to_chain_id
109
+ vault_address_to_chain_id = _fallback_vault_address_to_chain_id
139
110
 
140
111
 
141
112
  def prove_lock(
@@ -0,0 +1,446 @@
1
+ # Cartha CLI - Testnet Setup Guide
2
+
3
+ This guide will help you set up and use the Cartha CLI on the public testnet with real vault contracts.
4
+
5
+ ## Prerequisites
6
+
7
+ - Python 3.11
8
+ - Bittensor wallet (for subnet registration)
9
+ - Access to the testnet verifier URL
10
+ - Testnet TAO (required for subnet registration)
11
+ - EVM wallet (MetaMask or similar) with testnet USDC for locking
12
+
13
+ ## Step 0: Set Up Your EVM Wallet for Base Sepolia Testnet
14
+
15
+ Before you can lock funds, you need to configure your EVM wallet (MetaMask, Coinbase Wallet, etc.) to connect to Base Sepolia Testnet and get testnet tokens.
16
+
17
+ ### 0.1: Add Base Sepolia Testnet to Your Wallet
18
+
19
+ **For MetaMask:**
20
+
21
+ 1. Open MetaMask and click the network dropdown (usually shows "Ethereum Mainnet")
22
+ 2. Click "Add Network" or "Add a network manually"
23
+ 3. Enter the following network details:
24
+
25
+ ```
26
+ Network Name: Base Sepolia
27
+ RPC URL: https://sepolia.base.org
28
+ Chain ID: 84532
29
+ Currency Symbol: ETH
30
+ Block Explorer URL: https://sepolia.basescan.org
31
+ ```
32
+
33
+ 4. Click "Save" to add the network
34
+ 5. Switch to the "Base Sepolia" network
35
+
36
+ **For Other Wallets:**
37
+
38
+ - **Coinbase Wallet**: Go to Settings → Networks → Add Network, then enter the details above
39
+ - **WalletConnect-compatible wallets**: Use the same network details when connecting
40
+
41
+ **Quick Add (MetaMask):**
42
+
43
+ You can also use the [Chainlist](https://chainlist.org/) website:
44
+ 1. Visit https://chainlist.org/
45
+ 2. Search for "Base Sepolia"
46
+ 3. Click "Connect Wallet" and approve the connection
47
+ 4. Click "Add to MetaMask" and confirm
48
+
49
+ ### 0.2: Get Testnet ETH for Gas Fees
50
+
51
+ You'll need testnet ETH on Base Sepolia to pay for transaction gas fees. Get it from the official Optimism Superchain faucet:
52
+
53
+ 1. **Visit the Optimism Superchain Faucet**: https://console.optimism.io/faucet
54
+ 2. **Connect your wallet** (MetaMask or WalletConnect)
55
+ 3. **Select "Base Sepolia"** from the network dropdown
56
+ 4. **Enter your wallet address** (or it will auto-detect from your connected wallet)
57
+ 5. **Click "Request Tokens"** or similar button
58
+ 6. **Wait for confirmation** - You should receive testnet ETH within a few minutes
59
+
60
+ **Note**: The faucet may have rate limits (e.g., once per 24 hours per address). If you need more testnet ETH, you may need to wait or use a different address.
61
+
62
+ **Alternative Faucets** (if the main faucet is unavailable):
63
+ - Check Base Sepolia documentation for additional faucet options
64
+ - Join the Cartha Discord/Telegram for community faucet links
65
+
66
+ ### 0.3: Get Testnet USDC Tokens
67
+
68
+ Testnet USDC is required to lock funds in the Cartha vaults. You can claim testnet USDC from the Cartha faucet.
69
+
70
+ **To Get Testnet USDC:**
71
+
72
+ 1. **Visit the Cartha Faucet**: https://cartha.finance/faucet
73
+ 2. **Connect your wallet** (MetaMask, Coinbase Wallet, Talisman, or WalletConnect)
74
+ 3. **Make sure you're on Base Sepolia network** (Chain ID: 84532)
75
+ 4. **Click "Claim USDC"** button
76
+ 5. **Approve the transaction** in your wallet
77
+ 6. **Wait for confirmation** - You should receive 1,000,000 testnet USDC within a few minutes
78
+
79
+ **Faucet Details**:
80
+ - **Claim Amount**: 1,000,000 USDC per claim
81
+ - **Cooldown**: 24 hours between claims (per wallet address)
82
+ - **Network**: Base Sepolia (Chain ID: 84532)
83
+
84
+ **Note**: The faucet has a 24-hour cooldown period. After claiming, you'll need to wait 24 hours before you can claim again from the same wallet address.
85
+
86
+ **Testnet USDC Contract Address** (for reference):
87
+ - Base Sepolia: `0x2340D09c348930A76c8c2783EDa8610F699A51A8`
88
+
89
+ You can verify you received USDC by:
90
+ - Checking your wallet balance (should show USDC)
91
+ - Viewing your address on [BaseScan Sepolia](https://sepolia.basescan.org/)
92
+
93
+ ### Getting Testnet TAO
94
+
95
+ You'll need testnet TAO to register your hotkey to the subnet. Get testnet TAO from the faucet:
96
+
97
+ 🔗 **Testnet TAO Faucet**: <https://app.minersunion.ai/testnet-faucet>
98
+
99
+ Simply visit the faucet and request testnet TAO to your wallet address. You'll need TAO in your wallet to pay for subnet registration.
100
+
101
+ ## Installation
102
+
103
+ Install the Cartha CLI from PyPI:
104
+
105
+ ```bash
106
+ pip install cartha-cli
107
+ ```
108
+
109
+ Verify the installation:
110
+
111
+ ```bash
112
+ cartha --help
113
+ ```
114
+
115
+ ## Testnet Configuration
116
+
117
+ ### Environment Variables
118
+
119
+ Set the following environment variables:
120
+
121
+ ```bash
122
+ # Required: Testnet verifier URL
123
+ export CARTHA_VERIFIER_URL="https://cartha-verifier-826542474079.us-central1.run.app"
124
+
125
+ # Required: Bittensor network configuration
126
+ export CARTHA_NETWORK="test" # Use "test" for testnet
127
+ export CARTHA_NETUID=78 # Testnet subnet UID
128
+
129
+ # Optional: Custom wallet path
130
+ export BITTENSOR_WALLET_PATH="/path/to/wallet"
131
+ ```
132
+
133
+ ### Verify Configuration
134
+
135
+ ```bash
136
+ # Check CLI can access verifier
137
+ cartha --help
138
+
139
+ # Test verifier connectivity
140
+ curl "${CARTHA_VERIFIER_URL}/health"
141
+ ```
142
+
143
+ ## Testnet Workflow
144
+
145
+ ### Step 1: Verify Your EVM Wallet Setup
146
+
147
+ Before proceeding, make sure you have:
148
+
149
+ - ✅ Base Sepolia network added to your wallet
150
+ - ✅ Testnet ETH in your wallet (for gas fees)
151
+ - ✅ Testnet USDC in your wallet (contact team if needed)
152
+
153
+ You can verify your balances:
154
+ - Check ETH balance in your wallet
155
+ - Check USDC balance (should show as a token in your wallet)
156
+ - View on [BaseScan Sepolia](https://sepolia.basescan.org/address/YOUR_ADDRESS) to see all tokens
157
+
158
+ ### Step 2: Register Your Hotkey
159
+
160
+ Register your hotkey to the testnet subnet:
161
+
162
+ ```bash
163
+ cartha miner register \
164
+ --wallet-name <your-wallet-name> \
165
+ --wallet-hotkey <your-hotkey-name> \
166
+ --network test \
167
+ --netuid 78
168
+ ```
169
+
170
+ This will:
171
+
172
+ - Register your hotkey to subnet 78 (testnet)
173
+ - Fetch your slot UID
174
+ - Display your registration details
175
+
176
+ **Save the output** - you'll need your slot UID.
177
+
178
+ ### Step 3: Lock Funds Using Cartha Lock UI
179
+
180
+ Use the streamlined lock flow with the Cartha Lock UI:
181
+
182
+ ```bash
183
+ cartha vault lock \
184
+ --coldkey <your-coldkey-name> \
185
+ --hotkey <your-hotkey-name> \
186
+ --pool-id BTCUSD \
187
+ --amount 100.0 \
188
+ --lock-days 30 \
189
+ --owner-evm 0xYourEVMAddress
190
+
191
+ # Note: --chain-id and --vault-address are optional - CLI auto-matches them from pool-id!
192
+ ```
193
+
194
+ This command will:
195
+
196
+ 1. **Check Registration**: Verify your hotkey is registered on the subnet
197
+ 2. **Authenticate**: Sign a challenge message with your Bittensor hotkey to get a session token
198
+ 3. **Request Signature**: Get an EIP-712 LockRequest signature from the verifier
199
+ 4. **Open Cartha Lock UI**: Automatically opens the web interface in your browser with all parameters pre-filled
200
+ 5. **Phase 1 - Approve USDC**: Connect your wallet and approve USDC spending through the frontend. The CLI automatically detects when approval completes
201
+ 6. **Phase 2 - Lock Position**: Lock your USDC in the vault contract through the frontend
202
+ 7. **Auto-Detection**: The verifier automatically detects your `LockCreated` event and adds you to the upcoming epoch
203
+
204
+ **Important Notes**:
205
+ - Make sure you're connected to **Base Sepolia** network in your wallet (not Mainnet!)
206
+ - You'll need testnet USDC in your EVM wallet (contact team if you don't have any)
207
+ - The frontend supports MetaMask, Coinbase Wallet, Talisman, and WalletConnect
208
+ - Make sure the wallet you connect matches the `--owner-evm` address specified in the CLI
209
+ - The frontend includes wallet validation to prevent using the wrong address
210
+
211
+ **Transaction Flow**:
212
+ 1. **Approve USDC**: First transaction approves the vault to spend your USDC (handled in frontend)
213
+ 2. **Lock Position**: Second transaction locks your USDC in the vault (handled in frontend)
214
+ 3. Both transactions require gas fees (paid in testnet ETH)
215
+
216
+ **Managing Existing Positions**:
217
+ - Visit https://cartha.finance/manage to view all your locks
218
+ - Use "Extend" or "Top Up" buttons to modify existing positions
219
+
220
+ ### Step 4: Check Miner Status
221
+
222
+ Verify your miner status (no authentication required):
223
+
224
+ ```bash
225
+ cartha miner status \
226
+ --wallet-name <your-wallet-name> \
227
+ --wallet-hotkey <your-hotkey-name>
228
+
229
+ # Or with explicit slot UID
230
+ cartha miner status \
231
+ --wallet-name <your-wallet-name> \
232
+ --wallet-hotkey <your-hotkey-name> \
233
+ --slot <your-slot-uid>
234
+ ```
235
+
236
+ This will show:
237
+
238
+ - Miner state and pool information
239
+ - All active pools with amounts and expiration dates
240
+ - Days remaining countdown (with warnings for expiring pools)
241
+
242
+ ## Pool IDs and Vault Addresses
243
+
244
+ Pool IDs can be specified as either:
245
+ - **Human-readable names**: `BTCUSD`, `EUR/USD`, `ETH/USD`, etc.
246
+ - **Hex strings**: `0x...` (32 bytes)
247
+
248
+ The CLI automatically converts readable names to hex format and matches them to the correct vault address.
249
+
250
+ ### Available Testnet Pools (Base Sepolia)
251
+
252
+ | Pool Name | Pool ID (hex) | Vault Address |
253
+ |-----------|---------------|---------------|
254
+ | BTCUSD | `0xee62665949c883f9e0f6f002eac32e00bd59dfe6c34e92a91c37d6a8322d6489` | `0x471D86764B7F99b894ee38FcD3cEFF6EAB321b69` |
255
+ | ETH/USD | `0x0b43555ace6b39aae1b894097d0a9fc17f504c62fea598fa206cc6f5088e6e45` | `0xdB74B44957A71c95406C316f8d3c5571FA588248` |
256
+ | EUR/USD | `0xa9226449042e36bf6865099eec57482aa55e3ad026c315a0e4a692b776c318ca` | `0x3C4dAfAC827140B8a031d994b7e06A25B9f27BAD` |
257
+
258
+ **Note**: When using `cartha vault lock`, you can simply specify `--pool-id BTCUSD` and the CLI will automatically:
259
+ - Match the correct vault address for that pool
260
+ - Match the correct chain ID (Base Sepolia: 84532)
261
+
262
+ You don't need to manually specify `--vault-address` or `--chain-id` unless you want to override them.
263
+
264
+ See `testnet/pool_ids.py` for the complete pool mappings and helper functions.
265
+
266
+ ## Common Commands
267
+
268
+ ### Check CLI Version
269
+
270
+ ```bash
271
+ cartha version
272
+ ```
273
+
274
+ ### View Help
275
+
276
+ ```bash
277
+ cartha --help
278
+ cartha miner register --help
279
+ cartha vault lock --help
280
+ cartha miner status --help
281
+ ```
282
+
283
+ ### Register (Burned Registration)
284
+
285
+ ```bash
286
+ cartha miner register \
287
+ --wallet-name <name> \
288
+ --wallet-hotkey <hotkey> \
289
+ --network test \
290
+ --netuid 78 \
291
+ --burned
292
+ ```
293
+
294
+ ## Troubleshooting
295
+
296
+ ### "Verifier URL not found"
297
+
298
+ **Problem**: CLI can't connect to verifier
299
+
300
+ **Solution**:
301
+
302
+ ```bash
303
+ # Verify environment variable is set
304
+ echo $CARTHA_VERIFIER_URL
305
+
306
+ # Test verifier connectivity
307
+ curl "${CARTHA_VERIFIER_URL}/health"
308
+
309
+ # If using a different URL, update it
310
+ export CARTHA_VERIFIER_URL="https://cartha-verifier-826542474079.us-central1.run.app"
311
+ ```
312
+
313
+ ### "Hotkey not registered"
314
+
315
+ **Problem**: Hotkey is not registered on the subnet
316
+
317
+ **Solution**:
318
+
319
+ - Register your hotkey first using `cartha miner register`
320
+ - Verify you're using the correct network (`test`) and netuid (`78`)
321
+ - Check that you have testnet TAO in your wallet
322
+
323
+ ### "Wallet not found"
324
+
325
+ **Problem**: CLI can't find your Bittensor wallet
326
+
327
+ **Solution**:
328
+
329
+ ```bash
330
+ # Check default wallet location
331
+ ls ~/.bittensor/wallets/
332
+
333
+ # Or set custom path
334
+ export BITTENSOR_WALLET_PATH="/path/to/wallet"
335
+ ```
336
+
337
+ ### "Network error"
338
+
339
+ **Problem**: Can't connect to Bittensor network
340
+
341
+ **Solution**:
342
+
343
+ - Verify `CARTHA_NETWORK` is set to `"test"` for testnet
344
+ - Check your internet connection
345
+ - Try using a VPN if network is blocked
346
+
347
+ ### "Transaction failed"
348
+
349
+ **Problem**: MetaMask transaction failed
350
+
351
+ **Solution**:
352
+
353
+ - **Check Network**: Make sure you're on **Base Sepolia** network (not Mainnet or other networks)
354
+ - **Check Gas**: Ensure you have enough testnet ETH for gas fees
355
+ - **Check USDC**: Ensure you have enough testnet USDC in your wallet
356
+ - **Check Approval**: Make sure you've approved the vault to spend USDC (first transaction)
357
+ - **Verify Transaction Data**: Check that the transaction data matches what the CLI displayed
358
+ - **Check Network Congestion**: Base Sepolia may be slower than mainnet - wait a bit and retry
359
+
360
+ ### "Insufficient funds" or "Not enough ETH"
361
+
362
+ **Problem**: Don't have enough testnet ETH for gas
363
+
364
+ **Solution**:
365
+
366
+ - Visit https://console.optimism.io/faucet
367
+ - Select "Base Sepolia" network
368
+ - Request testnet ETH to your wallet address
369
+ - Wait a few minutes for the transaction to complete
370
+ - Retry your transaction
371
+
372
+ ### "USDC balance is zero" or "No USDC found"
373
+
374
+ **Problem**: Don't have testnet USDC tokens
375
+
376
+ **Solution**:
377
+
378
+ - Visit the Cartha faucet at https://cartha.finance/faucet
379
+ - Connect your wallet and claim 1,000,000 testnet USDC
380
+ - Note: There's a 24-hour cooldown between claims
381
+ - Verify receipt on [BaseScan Sepolia](https://sepolia.basescan.org/)
382
+
383
+ ### "Wrong wallet connected" or "Wallet address mismatch"
384
+
385
+ **Problem**: The frontend shows a warning that the connected wallet doesn't match the required owner address
386
+
387
+ **Solution**:
388
+
389
+ 1. **Disconnect your current wallet** using the "Disconnect" button in the frontend
390
+ 2. **Connect the correct wallet** that matches the `--owner-evm` address you specified in the CLI
391
+ 3. **Verify the address** - The frontend will show "Required Owner" vs "Connected Wallet" to help you identify the mismatch
392
+ 4. If you need to use a different address, restart the CLI command with the correct `--owner-evm` address
393
+
394
+ **Note**: The frontend includes automatic wallet validation to prevent this issue. Always ensure you connect the wallet that matches the address specified in the CLI command.
395
+
396
+ ## Testing Your Setup
397
+
398
+ ### Complete Testnet Checklist
399
+
400
+ Before starting, make sure you have:
401
+
402
+ - [ ] Python 3.11 installed
403
+ - [ ] `uv` package manager installed
404
+ - [ ] Bittensor wallet set up
405
+ - [ ] MetaMask (or other EVM wallet) installed
406
+ - [ ] Base Sepolia network added to MetaMask
407
+ - [ ] Testnet ETH in your wallet (from faucet)
408
+ - [ ] Testnet USDC in your wallet (from team)
409
+ - [ ] Testnet TAO in your Bittensor wallet (for registration)
410
+
411
+ ### Quick Test
412
+
413
+ ```bash
414
+ # 1. Register your hotkey
415
+ cartha miner register --wallet-name test --wallet-hotkey test --network test --netuid 78
416
+
417
+ # 2. Check miner status (no authentication needed)
418
+ cartha miner status --wallet-name test --wallet-hotkey test
419
+
420
+ # 3. Lock funds (interactive flow)
421
+ # Note: Make sure you're on Base Sepolia network in MetaMask!
422
+ # Chain ID and vault address are auto-detected from pool-id - no need to specify!
423
+ cartha vault lock \
424
+ --coldkey test \
425
+ --hotkey test \
426
+ --pool-id BTCUSD \
427
+ --amount 100.0 \
428
+ --lock-days 30 \
429
+ --owner-evm 0xYourEVMAddress
430
+ ```
431
+
432
+ **Important**:
433
+ - Chain ID (84532 for Base Sepolia) and vault address are **automatically detected** from the pool ID
434
+ - You only need to specify `--pool-id BTCUSD` (or `ETH/USD`, `EUR/USD`)
435
+ - The CLI will show you the auto-matched values before proceeding
436
+
437
+ ## Next Steps
438
+
439
+ - Check the [Main README](../README.md) for advanced usage
440
+ - Review [Validator Setup](../../cartha-validator/docs/TESTNET_SETUP.md) if running a validator
441
+ - Provide feedback via [GitHub Issues](https://github.com/your-org/cartha-cli/issues)
442
+
443
+ ## Additional Resources
444
+
445
+ - [CLI README](../README.md) - Full CLI documentation
446
+ - `testnet/pool_ids.py` - Pool ID helper functions for converting between readable names and hex format
@@ -0,0 +1,2 @@
1
+ """Testnet utilities for Cartha CLI."""
2
+
@@ -0,0 +1,208 @@
1
+ """Helper functions for generating and displaying human-readable pool IDs.
2
+
3
+ Pool IDs are bytes32 (32 bytes = 64 hex chars), so we can encode readable text
4
+ in hex format. This module provides helpers to convert between readable names
5
+ and hex pool IDs.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ # Predefined pool mappings (readable name -> hex pool ID)
11
+ # Base Sepolia testnet pool IDs from vault contracts (keccak256 hashes)
12
+ # Pool IDs are bytes32 (keccak256 hashes: 32 bytes = 64 hex chars + 0x prefix = 66 chars)
13
+ POOL_MAPPINGS: dict[str, str] = {
14
+ "BTCUSD": "0xee62665949c883f9e0f6f002eac32e00bd59dfe6c34e92a91c37d6a8322d6489", # BTC/USD (keccak256("BTC/USD"))
15
+ "ETHUSD": "0x0b43555ace6b39aae1b894097d0a9fc17f504c62fea598fa206cc6f5088e6e45", # ETH/USD (keccak256("ETH/USD"))
16
+ "EURUSD": "0xa9226449042e36bf6865099eec57482aa55e3ad026c315a0e4a692b776c318ca", # EUR/USD (keccak256("EUR/USD"))
17
+ }
18
+
19
+ # Reverse mapping (hex -> readable name)
20
+ POOL_NAMES: dict[str, str] = {v.lower(): k for k, v in POOL_MAPPINGS.items()}
21
+
22
+ # Pool ID to Vault Address mapping (Base Sepolia testnet)
23
+ # Each pool ID has its own dedicated vault address
24
+ VAULT_ADDRESSES: dict[str, str] = {
25
+ "BTCUSD": "0x471D86764B7F99b894ee38FcD3cEFF6EAB321b69", # BTC/USD Vault
26
+ "ETHUSD": "0xdB74B44957A71c95406C316f8d3c5571FA588248", # ETH/USD Vault
27
+ "EURUSD": "0x3C4dAfAC827140B8a031d994b7e06A25B9f27BAD", # EUR/USD Vault
28
+ }
29
+
30
+ # Pool ID (hex) to Vault Address mapping
31
+ POOL_ID_TO_VAULT: dict[str, str] = {
32
+ POOL_MAPPINGS["BTCUSD"].lower(): VAULT_ADDRESSES["BTCUSD"],
33
+ POOL_MAPPINGS["ETHUSD"].lower(): VAULT_ADDRESSES["ETHUSD"],
34
+ POOL_MAPPINGS["EURUSD"].lower(): VAULT_ADDRESSES["EURUSD"],
35
+ }
36
+
37
+ # Vault Address to Chain ID mapping (Base Sepolia testnet)
38
+ # All testnet vaults are on Base Sepolia (chain ID 84532)
39
+ VAULT_TO_CHAIN_ID: dict[str, int] = {
40
+ VAULT_ADDRESSES["BTCUSD"].lower(): 84532, # Base Sepolia
41
+ VAULT_ADDRESSES["ETHUSD"].lower(): 84532, # Base Sepolia
42
+ VAULT_ADDRESSES["EURUSD"].lower(): 84532, # Base Sepolia
43
+ }
44
+
45
+ # Pool ID (hex) to Chain ID mapping
46
+ POOL_ID_TO_CHAIN_ID: dict[str, int] = {
47
+ POOL_MAPPINGS["BTCUSD"].lower(): 84532, # Base Sepolia
48
+ POOL_MAPPINGS["ETHUSD"].lower(): 84532, # Base Sepolia
49
+ POOL_MAPPINGS["EURUSD"].lower(): 84532, # Base Sepolia
50
+ }
51
+
52
+
53
+ def pool_id_to_vault_address(pool_id: str) -> str | None:
54
+ """Get vault address for a given pool ID.
55
+
56
+ Args:
57
+ pool_id: Pool ID in hex format (bytes32)
58
+
59
+ Returns:
60
+ Vault address if found, None otherwise
61
+ """
62
+ pool_id_lower = pool_id.lower().strip()
63
+ if not pool_id_lower.startswith("0x"):
64
+ pool_id_lower = "0x" + pool_id_lower
65
+
66
+ return POOL_ID_TO_VAULT.get(pool_id_lower)
67
+
68
+
69
+ def vault_address_to_pool_id(vault_address: str) -> str | None:
70
+ """Get pool ID for a given vault address.
71
+
72
+ Args:
73
+ vault_address: Vault contract address
74
+
75
+ Returns:
76
+ Pool ID if found, None otherwise
77
+ """
78
+ vault_lower = vault_address.lower().strip()
79
+ if not vault_lower.startswith("0x"):
80
+ vault_lower = "0x" + vault_lower
81
+
82
+ # Reverse lookup
83
+ for pool_id, vault in POOL_ID_TO_VAULT.items():
84
+ if vault.lower() == vault_lower:
85
+ return pool_id
86
+ return None
87
+
88
+
89
+ def pool_id_to_chain_id(pool_id: str) -> int | None:
90
+ """Get chain ID for a given pool ID.
91
+
92
+ Args:
93
+ pool_id: Pool ID in hex format (bytes32)
94
+
95
+ Returns:
96
+ Chain ID if found, None otherwise
97
+ """
98
+ pool_id_lower = pool_id.lower().strip()
99
+ if not pool_id_lower.startswith("0x"):
100
+ pool_id_lower = "0x" + pool_id_lower
101
+
102
+ return POOL_ID_TO_CHAIN_ID.get(pool_id_lower)
103
+
104
+
105
+ def vault_address_to_chain_id(vault_address: str) -> int | None:
106
+ """Get chain ID for a given vault address.
107
+
108
+ Args:
109
+ vault_address: Vault contract address
110
+
111
+ Returns:
112
+ Chain ID if found, None otherwise
113
+ """
114
+ vault_lower = vault_address.lower().strip()
115
+ if not vault_lower.startswith("0x"):
116
+ vault_lower = "0x" + vault_lower
117
+
118
+ return VAULT_TO_CHAIN_ID.get(vault_lower)
119
+
120
+
121
+ def pool_name_to_id(pool_name: str) -> str:
122
+ """Convert a readable pool name to hex pool ID.
123
+
124
+ Args:
125
+ pool_name: Readable name (e.g., "USDEUR", "XAUUSD")
126
+
127
+ Returns:
128
+ Hex pool ID (bytes32 format)
129
+
130
+ Examples:
131
+ >>> pool_name_to_id("USDEUR")
132
+ '0x0000000000000000000000000000000000000000000000000000000000555344455552'
133
+ """
134
+ pool_name_upper = pool_name.upper()
135
+ if pool_name_upper in POOL_MAPPINGS:
136
+ return POOL_MAPPINGS[pool_name_upper]
137
+
138
+ # If not in predefined mappings, encode the name as hex
139
+ # Pad to 32 bytes (64 hex chars), right-padded (data at end, zeros at beginning)
140
+ name_bytes = pool_name.encode("utf-8")
141
+ if len(name_bytes) > 32:
142
+ raise ValueError(f"Pool name too long: {pool_name} (max 32 bytes)")
143
+
144
+ # Right-pad with zeros to 32 bytes (data at end, zeros at beginning)
145
+ padded = name_bytes.rjust(32, b"\x00")
146
+ hex_id = "0x" + padded.hex()
147
+ # Validate length
148
+ if len(hex_id) != 66: # 0x + 64 hex chars
149
+ raise ValueError(f"Generated pool_id has incorrect length: {len(hex_id)} (expected 66)")
150
+ return hex_id
151
+
152
+
153
+ def pool_id_to_name(pool_id: str) -> str | None:
154
+ """Convert a hex pool ID to readable name if available.
155
+
156
+ Args:
157
+ pool_id: Hex pool ID (bytes32 format)
158
+
159
+ Returns:
160
+ Readable name if found, None otherwise
161
+
162
+ Examples:
163
+ >>> pool_id_to_name("0x0000000000000000000000000000000000000000000000000000000000555344455552")
164
+ 'USDEUR'
165
+ """
166
+ pool_id_lower = pool_id.lower()
167
+ if pool_id_lower in POOL_NAMES:
168
+ return POOL_NAMES[pool_id_lower]
169
+
170
+ # Try to decode from hex
171
+ try:
172
+ # Remove 0x prefix
173
+ hex_str = pool_id_lower.removeprefix("0x")
174
+ # Convert to bytes
175
+ pool_bytes = bytes.fromhex(hex_str)
176
+ # Try to decode as UTF-8 (remove trailing zeros)
177
+ name = pool_bytes.rstrip(b"\x00").decode("utf-8", errors="ignore")
178
+ if name and name.isprintable():
179
+ return name
180
+ except Exception:
181
+ pass
182
+
183
+ return None
184
+
185
+
186
+ def format_pool_id(pool_id: str) -> str:
187
+ """Format a pool ID for display (shows readable name if available).
188
+
189
+ Args:
190
+ pool_id: Hex pool ID
191
+
192
+ Returns:
193
+ Formatted string: "USDEUR (0x...)" or just "0x..." if no name found
194
+ """
195
+ name = pool_id_to_name(pool_id)
196
+ if name:
197
+ return f"{name} ({pool_id})"
198
+ return pool_id
199
+
200
+
201
+ def list_pools() -> dict[str, str]:
202
+ """List all predefined pools.
203
+
204
+ Returns:
205
+ Dictionary mapping readable names to hex pool IDs
206
+ """
207
+ return POOL_MAPPINGS.copy()
208
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cartha-cli
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: CLI utilities for Cartha subnet miners.
5
5
  Project-URL: Homepage, https://cartha.finance
6
6
  Project-URL: Repository, https://github.com/General-Tao-Ventures/cartha-cli
@@ -15,14 +15,17 @@ cartha_cli/commands/health.py,sha256=NRwmIultxUzAe7udOOBIdkcdGG5KsE_kuCs43LZObGk
15
15
  cartha_cli/commands/help.py,sha256=6ubfWtmjXfCtp6L_PYvn7rR7m5C_pp-iEjtRc6BS0GA,1721
16
16
  cartha_cli/commands/miner_password.py,sha256=7cbcyrJ9KzCyJ68_174U_CXjBUt9BaYhgKAycRpv7AE,11078
17
17
  cartha_cli/commands/miner_status.py,sha256=tWlCWcuwm9NEd4USuCLp_6qObikX2odc2e7m6Y_vNrU,21873
18
- cartha_cli/commands/pair_status.py,sha256=Q_CTi-7vrvpe0XYiuf_RFdFNXiBcs84xLcTYguxb4ho,19979
19
- cartha_cli/commands/pools.py,sha256=hXtqRmBLfcMe_FJiW_rcVcttyt7jMX37n0mZAXSnmOU,4661
20
- cartha_cli/commands/prove_lock.py,sha256=A5AZkfqCLbDio4idud4XV-ktYRhYVOA22WhqPojyFc8,61480
18
+ cartha_cli/commands/pair_status.py,sha256=LoU-fA1MXuWZGHNmeKPMjwvNw30Yn094ZD1EC0-WXVc,19978
19
+ cartha_cli/commands/pools.py,sha256=P02SEp23a7OdrgNj6AaiJTnQ9K_QrI300DzucA6HH8A,3884
20
+ cartha_cli/commands/prove_lock.py,sha256=ihcZLrYcc9Pr4X75K9cgaDEod0Sjjyj58sAUPAhRQEo,60268
21
21
  cartha_cli/commands/register.py,sha256=sxbYO0V4NucOKLZpaFoVnhFDHLSLDHREoMtN9DjyLsM,10227
22
22
  cartha_cli/commands/shared_options.py,sha256=itHzJSgxuKQxUVOh1_jVTcMQXjI3PPzexQyhqIbabxc,5874
23
23
  cartha_cli/commands/version.py,sha256=u5oeccQzK0LLcCbgZm0U8-Vslk5vB_lVvW3xT5HPeTg,456
24
- cartha_cli-1.0.2.dist-info/METADATA,sha256=oCfBEiLZfg8QSFW-Ml9smIh0WNPG-vQ2QKbC4oKZG6c,5794
25
- cartha_cli-1.0.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
26
- cartha_cli-1.0.2.dist-info/entry_points.txt,sha256=sTYVMgb9l0fuJibUtWpGnIoDmgHinne97G4Y_cCwC-U,43
27
- cartha_cli-1.0.2.dist-info/licenses/LICENSE,sha256=B4UCiDn13m4xYwIl4TMKfbuKw7kh9pg4c81rJecxHSo,1076
28
- cartha_cli-1.0.2.dist-info/RECORD,,
24
+ cartha_cli/testnet/README.md,sha256=kWKaLtq6t_46W-mvXkSaLi2fjXDELLk5ntVGkogiUY0,14511
25
+ cartha_cli/testnet/__init__.py,sha256=xreJMXs-ZKTkPtUQBR5xdY7ImOyUiF7WKG6bv9J9aBM,41
26
+ cartha_cli/testnet/pool_ids.py,sha256=0jvQ6tvc6sL0aGKkl31KXM6ngVpUboYiABY5SDMaRCQ,6747
27
+ cartha_cli-1.0.3.dist-info/METADATA,sha256=5c0z7KdAKD3ZejILXjQF9GI6WvIUcqxUdmgv-qhm1eY,5794
28
+ cartha_cli-1.0.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
29
+ cartha_cli-1.0.3.dist-info/entry_points.txt,sha256=sTYVMgb9l0fuJibUtWpGnIoDmgHinne97G4Y_cCwC-U,43
30
+ cartha_cli-1.0.3.dist-info/licenses/LICENSE,sha256=B4UCiDn13m4xYwIl4TMKfbuKw7kh9pg4c81rJecxHSo,1076
31
+ cartha_cli-1.0.3.dist-info/RECORD,,