apow-cli 0.4.1 → 0.6.1

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.
package/dist/index.js CHANGED
@@ -170,27 +170,10 @@ async function setupWizard() {
170
170
  console.log("");
171
171
  // Step 2: RPC
172
172
  console.log(` ${ui.bold("Step 2/3: RPC")}`);
173
- const rpcUrl = await ui.prompt("Base RPC URL", "https://mainnet.base.org");
174
- values.RPC_URL = rpcUrl;
175
- // Validate RPC connectivity
176
- try {
177
- const { createPublicClient, http } = await Promise.resolve().then(() => __importStar(require("viem")));
178
- const { base, baseSepolia } = await Promise.resolve().then(() => __importStar(require("viem/chains")));
179
- const isSepolia = rpcUrl.toLowerCase().includes("sepolia");
180
- const testClient = createPublicClient({
181
- chain: isSepolia ? baseSepolia : base,
182
- transport: http(rpcUrl),
183
- });
184
- const blockNumber = await testClient.getBlockNumber();
185
- const networkName = isSepolia ? "Base Sepolia" : "Base mainnet";
186
- ui.ok(`Connected — ${networkName}, block #${blockNumber.toLocaleString()}`);
187
- if (isSepolia)
188
- values.CHAIN = "baseSepolia";
189
- }
190
- catch {
191
- ui.fail("Could not connect to RPC");
192
- ui.hint("Continuing anyway — you can fix RPC_URL in .env later");
193
- }
173
+ console.log(` ${ui.dim("Default: Alchemy x402 — premium RPC paid automatically")}`);
174
+ console.log(` ${ui.dim("via USDC in your mining wallet. No API key needed.")}`);
175
+ console.log(` ${ui.dim("To use a custom RPC, set RPC_URL in .env after setup.")}`);
176
+ ui.ok("RPC: Alchemy x402 (default)");
194
177
  console.log("");
195
178
  // Step 3: LLM (for minting)
196
179
  console.log(` ${ui.bold("Step 3/3: LLM Provider (for minting)")}`);
@@ -277,10 +260,12 @@ async function main() {
277
260
  });
278
261
  program
279
262
  .command("fund")
280
- .description("Fund your wallet — bridge SOL ETH on Base, or show deposit address")
281
- .option("--solana", "Bridge from Solana")
263
+ .description("Fund your wallet — bridge from Solana/Ethereum or swap on Base")
264
+ .option("--chain <chain>", "Source chain: solana, ethereum, base")
265
+ .option("--token <token>", "Source token: sol, eth, usdc")
282
266
  .option("--key <base58>", "Solana private key for direct signing")
283
267
  .option("--amount <eth>", "Target ETH amount (default: 0.005)")
268
+ .option("--no-swap", "Skip auto-split after bridging")
284
269
  .hook("preAction", async () => {
285
270
  await (0, preflight_1.runPreflight)("readonly");
286
271
  })
@@ -513,6 +498,8 @@ async function main() {
513
498
  port: 3847,
514
499
  walletsPath,
515
500
  rpcUrl: config_1.config.rpcUrl,
501
+ useX402: config_1.config.useX402,
502
+ privateKey: config_1.config.privateKey,
516
503
  miningAgentAddress: config_1.config.miningAgentAddress,
517
504
  agentCoinAddress: config_1.config.agentCoinAddress,
518
505
  });
package/dist/preflight.js CHANGED
@@ -38,11 +38,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.runPreflight = runPreflight;
40
40
  const viem_1 = require("viem");
41
+ const chains_1 = require("viem/chains");
41
42
  const AgentCoin_json_1 = __importDefault(require("./abi/AgentCoin.json"));
42
43
  const config_1 = require("./config");
43
44
  const wallet_1 = require("./wallet");
45
+ const x402_1 = require("./x402");
44
46
  const ui = __importStar(require("./ui"));
45
47
  const agentCoinAbi = AgentCoin_json_1.default;
48
+ const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
49
+ const USDC_DECIMALS = 6;
50
+ const erc20BalanceAbi = [
51
+ {
52
+ type: "function",
53
+ name: "balanceOf",
54
+ inputs: [{ name: "account", type: "address" }],
55
+ outputs: [{ name: "", type: "uint256" }],
56
+ stateMutability: "view",
57
+ },
58
+ ];
46
59
  async function runPreflight(level) {
47
60
  const results = [];
48
61
  // Check 1: Contract addresses set
@@ -79,6 +92,45 @@ async function runPreflight(level) {
79
92
  fix: "Check internet connection or update RPC_URL in .env",
80
93
  });
81
94
  }
95
+ // Check x402: USDC balance when x402 mode is active
96
+ if (config_1.config.useX402 && wallet_1.account) {
97
+ try {
98
+ // Use a separate lightweight client to avoid chicken-and-egg
99
+ // (can't use x402 to check if we can pay for x402)
100
+ const checkClient = (0, viem_1.createPublicClient)({
101
+ chain: chains_1.base,
102
+ transport: (0, viem_1.http)("https://mainnet.base.org"),
103
+ });
104
+ const usdcBalance = (await checkClient.readContract({
105
+ address: USDC_ADDRESS,
106
+ abi: erc20BalanceAbi,
107
+ functionName: "balanceOf",
108
+ args: [wallet_1.account.address],
109
+ }));
110
+ if (usdcBalance === 0n) {
111
+ ui.warn("No USDC balance — x402 RPC requires USDC on Base for payment");
112
+ ui.hint(`Send USDC to ${wallet_1.account.address} on Base, or set RPC_URL in .env to use a free RPC`);
113
+ ui.hint("Falling back to public RPC (https://mainnet.base.org)");
114
+ config_1.config.useX402 = false;
115
+ (0, x402_1.resetX402)();
116
+ (0, wallet_1.reinitClients)();
117
+ }
118
+ else {
119
+ const formatted = (0, viem_1.formatUnits)(usdcBalance, USDC_DECIMALS);
120
+ results.push({
121
+ label: `RPC: Alchemy x402 (${formatted} USDC available)`,
122
+ passed: true,
123
+ });
124
+ }
125
+ }
126
+ catch {
127
+ // USDC check failed — fall back silently
128
+ ui.warn("Could not check USDC balance — falling back to public RPC");
129
+ config_1.config.useX402 = false;
130
+ (0, x402_1.resetX402)();
131
+ (0, wallet_1.reinitClients)();
132
+ }
133
+ }
82
134
  if (level === "wallet" || level === "mining") {
83
135
  // Check 3: Private key valid
84
136
  if (wallet_1.account) {
package/dist/wallet.js CHANGED
@@ -1,16 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.walletClient = exports.account = exports.publicClient = void 0;
4
+ exports.reinitClients = reinitClients;
4
5
  exports.requireWallet = requireWallet;
5
6
  exports.getEthBalance = getEthBalance;
6
7
  const viem_1 = require("viem");
7
8
  const accounts_1 = require("viem/accounts");
8
9
  const erc8021_1 = require("ox/erc8021");
9
10
  const config_1 = require("./config");
11
+ const x402_1 = require("./x402");
10
12
  const DATA_SUFFIX = erc8021_1.Attribution.toDataSuffix({ codes: ["bc_6wfeb1kd"] });
13
+ function getTransport() {
14
+ if (config_1.config.useX402 && config_1.config.privateKey) {
15
+ return (0, x402_1.createX402Transport)(config_1.config.privateKey);
16
+ }
17
+ return (0, viem_1.http)(config_1.config.rpcUrl);
18
+ }
19
+ const transport = getTransport();
11
20
  exports.publicClient = (0, viem_1.createPublicClient)({
12
21
  chain: config_1.config.chain,
13
- transport: (0, viem_1.http)(config_1.config.rpcUrl),
22
+ transport,
14
23
  });
15
24
  exports.account = config_1.config.privateKey
16
25
  ? (0, accounts_1.privateKeyToAccount)(config_1.config.privateKey)
@@ -19,10 +28,23 @@ exports.walletClient = exports.account
19
28
  ? (0, viem_1.createWalletClient)({
20
29
  account: exports.account,
21
30
  chain: config_1.config.chain,
22
- transport: (0, viem_1.http)(config_1.config.rpcUrl),
31
+ transport,
23
32
  dataSuffix: DATA_SUFFIX,
24
33
  })
25
34
  : null;
35
+ /** Reinitialize clients after config changes (e.g., x402 fallback). */
36
+ function reinitClients() {
37
+ const t = getTransport();
38
+ exports.publicClient = (0, viem_1.createPublicClient)({ chain: config_1.config.chain, transport: t });
39
+ if (exports.account) {
40
+ exports.walletClient = (0, viem_1.createWalletClient)({
41
+ account: exports.account,
42
+ chain: config_1.config.chain,
43
+ transport: t,
44
+ dataSuffix: DATA_SUFFIX,
45
+ });
46
+ }
47
+ }
26
48
  function requireWallet() {
27
49
  if (!exports.account || !exports.walletClient) {
28
50
  throw new Error("Wallet is not configured. Set PRIVATE_KEY in .env.");
package/dist/x402.js ADDED
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createX402Transport = createX402Transport;
4
+ exports.resetX402 = resetX402;
5
+ const accounts_1 = require("viem/accounts");
6
+ const viem_1 = require("viem");
7
+ const ALCHEMY_X402_BASE = "https://x402.alchemy.com/rpc/base-mainnet";
8
+ let _paidFetch = null;
9
+ /* eslint-disable @typescript-eslint/no-require-imports */
10
+ function getPaidFetchSync(privateKey) {
11
+ if (_paidFetch)
12
+ return _paidFetch;
13
+ // Use require() to avoid subpath module resolution issues with CommonJS.
14
+ // The x402 packages use `exports` maps which require "node16"/"bundler"
15
+ // moduleResolution — but this project uses classic "Node" resolution.
16
+ const { x402Client } = require("@x402/core/client");
17
+ const { ExactEvmScheme } = require("@x402/evm/exact/client");
18
+ const { toClientEvmSigner } = require("@x402/evm");
19
+ const { wrapFetchWithPayment } = require("@x402/fetch");
20
+ const account = (0, accounts_1.privateKeyToAccount)(privateKey);
21
+ const signer = toClientEvmSigner(account);
22
+ const client = new x402Client();
23
+ client.register("eip155:*", new ExactEvmScheme(signer));
24
+ _paidFetch = wrapFetchWithPayment(fetch, client);
25
+ return _paidFetch;
26
+ }
27
+ function createX402Transport(privateKey) {
28
+ return (0, viem_1.custom)({
29
+ async request({ method, params }) {
30
+ const paidFetch = getPaidFetchSync(privateKey);
31
+ const response = await paidFetch(ALCHEMY_X402_BASE, {
32
+ method: "POST",
33
+ headers: { "Content-Type": "application/json" },
34
+ body: JSON.stringify({ jsonrpc: "2.0", method, params, id: 1 }),
35
+ });
36
+ const data = (await response.json());
37
+ if (data.error)
38
+ throw new Error(data.error.message);
39
+ return data.result;
40
+ },
41
+ });
42
+ }
43
+ function resetX402() {
44
+ _paidFetch = null;
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apow-cli",
3
- "version": "0.4.1",
3
+ "version": "0.6.1",
4
4
  "description": "Mine AGENT tokens on Base L2 with Agentic Proof of Work",
5
5
  "keywords": [
6
6
  "apow",
@@ -40,6 +40,8 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@solana/web3.js": "^1.98.0",
43
+ "@x402/evm": "^2.8.0",
44
+ "@x402/fetch": "^2.8.0",
43
45
  "commander": "^14.0.0",
44
46
  "dotenv": "^17.2.3",
45
47
  "openai": "^6.6.0",
package/skill.md CHANGED
@@ -25,14 +25,7 @@ metadata:
25
25
  configure the miner, mint, and mine. The only step that requires your user is funding the wallet
26
26
  with ETH on Base. Everything else you handle yourself.
27
27
 
28
- > **IMPORTANT: You need a dedicated RPC endpoint.** The default public RPC (`https://mainnet.base.org`) has aggressive rate limits and **will cause minting and mining to fail**. Before starting, get a free Alchemy endpoint:
29
- >
30
- > 1. Go to [alchemy.com](https://www.alchemy.com/) and sign up (free, no credit card)
31
- > 2. Click **Create new app** → Name: `apow-miner` → Chain: **Base** → Network: **Base Mainnet**
32
- > 3. Copy the **HTTPS** URL: `https://base-mainnet.g.alchemy.com/v2/YOUR_API_KEY`
33
- > 4. Set `RPC_URL` to this URL in your `.env`
34
- >
35
- > Alchemy's free tier (300M compute units/month) is more than enough. See [RPC Recommendations](#rpc-recommendations) for alternatives.
28
+ > **RPC:** The CLI uses [Alchemy x402](https://x402.alchemy.com/) by default -- a premium Base RPC that charges per-request via USDC in your mining wallet. No API key, no account, no rate limits. Just fund your wallet with USDC (the `apow fund` command handles this automatically). If no USDC is available, it falls back to the public RPC. To use a custom RPC, set `RPC_URL` in `.env`.
36
29
 
37
30
  ---
38
31
 
@@ -78,10 +71,11 @@ MINING_AGENT_ADDRESS=0xB7caD3ca5F2BD8aEC2Eb67d6E8D448099B3bC03D
78
71
  AGENT_COIN_ADDRESS=0x12577CF0D8a07363224D6909c54C056A183e13b3
79
72
  EOF
80
73
 
81
- # 3. Fund the wallet (bridge from Solana or send ETH on Base)
82
- npx apow-cli fund --solana # interactive bridge SOL → ETH on Base
83
- # Or: npx apow-cli fund --solana --key <base58> # direct signing (~20s)
84
- # Or: ask your user to send ≥0.005 ETH on Base directly
74
+ # 3. Fund the wallet (bridge from any chain, auto-splits into ETH + USDC)
75
+ npx apow-cli fund --chain solana --token sol # bridge SOL → ETH+USDC on Base
76
+ # Or: npx apow-cli fund --chain solana --token sol --key <base58> # direct signing (~20s)
77
+ # Or: npx apow-cli fund --chain ethereum --token eth # bridge from Ethereum mainnet
78
+ # Or: ask your user to send ETH + USDC on Base directly
85
79
 
86
80
  # 4. Mint + mine (fully autonomous from here)
87
81
  npx apow-cli mint
@@ -117,7 +111,7 @@ The miner client validates locally before submitting.
117
111
  |---|---|
118
112
  | **Node.js** | v18 or higher |
119
113
  | **Base wallet** | A private key with ETH on Base (for gas + mint fee) |
120
- | **LLM access** | API key (OpenAI, Anthropic, Gemini, DeepSeek, Qwen), local Ollama, or Claude Code / Codex CLI (**required for minting only**) |
114
+ | **LLM access** | API key (OpenAI, Gemini, DeepSeek, Qwen, or Anthropic) or local Ollama (**required for minting only**) |
121
115
  | **git** | Only if installing from source (not needed for npm) |
122
116
 
123
117
  ---
@@ -158,26 +152,32 @@ Your mining wallet needs ETH on Base for gas and the mint fee.
158
152
 
159
153
  ### Built-in Bridge: `apow fund` (Recommended)
160
154
 
161
- The CLI has a built-in cross-chain bridge for Solana users:
155
+ The CLI accepts deposits in 6 forms across 3 chains, auto-bridges to Base, and auto-splits into ETH (gas) + USDC (x402 RPC):
162
156
 
163
157
  ```bash
164
- npx apow-cli fund # Interactive: choose funding method
165
- npx apow-cli fund --solana # Deposit address + QR code
166
- npx apow-cli fund --solana --key <base58> # Direct Solana signing (~20s)
167
- npx apow-cli fund --solana --amount 0.01 # Custom ETH target
158
+ npx apow-cli fund # Interactive: choose chain + token
159
+ npx apow-cli fund --chain solana --token sol # Bridge SOL → ETH+USDC on Base
160
+ npx apow-cli fund --chain solana --token sol --key <b58> # Direct Solana signing (~20s)
161
+ npx apow-cli fund --chain solana --token usdc # Bridge Solana USDC → Base
162
+ npx apow-cli fund --chain ethereum --token eth # Bridge ETH from mainnet
163
+ npx apow-cli fund --chain ethereum --token usdc # Bridge USDC from mainnet
164
+ npx apow-cli fund --chain base # Show address, wait for deposit
165
+ npx apow-cli fund --chain base --no-swap # Skip auto-split
168
166
  ```
169
167
 
170
- **Three funding paths:**
168
+ **Bridge methods per chain:**
169
+
170
+ | Chain | Direct signing | Deposit address |
171
+ |-------|---------------|-----------------|
172
+ | Solana | deBridge DLN (~20s, `--key`) | Squid Router (~1-3 min) |
173
+ | Ethereum | deBridge DLN (~20s, uses PRIVATE_KEY on mainnet) | Squid Router (~1-3 min) |
174
+ | Base | N/A (already on Base) | Show address + QR code |
171
175
 
172
- | Path | How it works | Speed | Requires Solana key? |
173
- |------|-------------|-------|---------------------|
174
- | Direct signing | deBridge DLN signs + submits via your Solana keypair | ~20 seconds | Yes (`--key`) |
175
- | Deposit address | Squid Router generates a Solana address; send from any wallet | ~1-3 minutes | No |
176
- | Manual | Shows your Base address + QR code | Varies | No |
176
+ **Auto-split:** After bridging, the CLI checks ETH and USDC balances. If either is below the minimum (0.003 ETH for gas, 2.00 USDC for x402 RPC), it swaps the needed amount via Uniswap V3 on Base. Use `--no-swap` to skip.
177
177
 
178
- **Direct signing (`--key`):** Provide your base58 Solana secret key. The CLI calls deBridge DLN to create a bridge order, signs the Solana transaction locally, submits it, and polls until ETH arrives on Base. No API key needed.
178
+ **Direct signing (Solana `--key`):** Provide your base58 Solana secret key. The CLI calls deBridge DLN to create a bridge order, signs the Solana transaction locally, submits it, and polls until funds arrive on Base. No API key needed.
179
179
 
180
- **Deposit address (`--solana` without `--key`):** Requires `SQUID_INTEGRATOR_ID` in `.env` (free, apply at [squidrouter.com](https://app.squidrouter.com/)). Generates a one-time Solana deposit address with a QR code. Send SOL from any wallet (Phantom, Backpack, etc.) and the bridge handles the rest.
180
+ **Deposit address (no `--key`):** Requires `SQUID_INTEGRATOR_ID` in `.env` (free, apply at [squidrouter.com](https://app.squidrouter.com/)). Generates a one-time deposit address with a QR code. Send tokens from any wallet and the bridge handles the rest.
181
181
 
182
182
  ### Manual Funding Options
183
183
 
@@ -247,7 +247,7 @@ AGENT_COIN_ADDRESS=0x12577CF0D8a07363224D6909c54C056A183e13b3
247
247
 
248
248
  # === LLM Configuration (required for minting only; mining uses optimized solving) ===
249
249
 
250
- # Provider: "openai" | "anthropic" | "ollama" | "gemini" | "deepseek" | "qwen" | "claude-code" | "codex"
250
+ # Provider: "openai" | "gemini" | "deepseek" | "qwen" | "anthropic" | "ollama"
251
251
  LLM_PROVIDER=openai
252
252
 
253
253
  # API key (not required if LLM_PROVIDER=ollama)
@@ -273,32 +273,30 @@ CHAIN=base
273
273
  | `PRIVATE_KEY` | Yes | - | Wallet private key (0x + 64 hex chars) |
274
274
  | `MINING_AGENT_ADDRESS` | Yes | - | Deployed MiningAgent contract address |
275
275
  | `AGENT_COIN_ADDRESS` | Yes | - | Deployed AgentCoin contract address |
276
- | `LLM_PROVIDER` | For minting | `openai` | LLM provider for minting: `openai`, `anthropic`, `ollama`, `gemini`, `deepseek`, `qwen`, `claude-code`, or `codex`. Not needed for mining. |
277
- | `LLM_API_KEY` | For minting | - | API key for minting. Falls back to `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` / `DEEPSEEK_API_KEY` / `DASHSCOPE_API_KEY` per provider. Not needed for `ollama`, `claude-code`, `codex`, or mining. |
276
+ | `LLM_PROVIDER` | For minting | `openai` | LLM provider for minting: `openai`, `gemini`, `deepseek`, `qwen`, `anthropic`, or `ollama`. Not needed for mining. |
277
+ | `LLM_API_KEY` | For minting | - | API key for minting. Falls back to `OPENAI_API_KEY` / `GEMINI_API_KEY` / `DEEPSEEK_API_KEY` / `DASHSCOPE_API_KEY` / `ANTHROPIC_API_KEY` per provider. Not needed for `ollama` or mining. |
278
278
  | `LLM_MODEL` | For minting | `gpt-4o-mini` | Model identifier passed to the provider (minting only) |
279
279
  | `MINER_THREADS` | No | All CPU cores | Number of threads for parallel nonce grinding |
280
- | `RPC_URL` | **Strongly recommended** | `https://mainnet.base.org` | Base JSON-RPC endpoint. **The default public RPC is unreliable. Use Alchemy (free) or another dedicated provider.** |
280
+ | `RPC_URL` | No | Alchemy x402 | Base JSON-RPC endpoint. Default uses Alchemy x402 (premium, paid via USDC). Set to override with a custom endpoint. |
281
281
  | `CHAIN` | No | `base` | Network selector; auto-detects `baseSepolia` if RPC URL contains "sepolia" |
282
- | `SOLANA_RPC_URL` | No | `https://api.mainnet-beta.solana.com` | Solana RPC endpoint (only for `apow fund --solana`) |
282
+ | `SOLANA_RPC_URL` | No | `https://api.mainnet-beta.solana.com` | Solana RPC endpoint (only for `apow fund --chain solana`) |
283
+ | `ETHEREUM_RPC_URL` | No | `https://ethereum-rpc.publicnode.com` | Ethereum mainnet RPC (only for `apow fund --chain ethereum`) |
283
284
  | `SQUID_INTEGRATOR_ID` | No | - | Squid Router integrator ID for deposit address flow (free at [squidrouter.com](https://app.squidrouter.com/)) |
284
285
 
285
286
  ### LLM Provider Recommendations (for Minting)
286
287
 
287
288
  > An LLM is only needed for **minting** your Mining Rig NFT (one-time identity verification). Mining uses optimized algorithmic SMHL solving, with no LLM needed.
288
289
  >
289
- > **For AI agents:** Use an API-based provider (OpenAI, Anthropic, Gemini, DeepSeek, or Qwen) for minting. Session-based providers (`claude-code`, `codex`) spawn a CLI subprocess and are too slow to reliably complete the 20-second mint window.
290
+ > An LLM is only needed for **minting** your Mining Rig NFT (one-time identity verification). Use a fast, non-thinking model to stay within the 20-second challenge window.
290
291
 
291
292
  | Provider | Model | Cost per call | Notes |
292
293
  |---|---|---|---|
293
- | OpenAI | `gpt-4o-mini` | ~$0.001 | **Recommended for agents.** Cheapest, fastest, reliable |
294
+ | OpenAI | `gpt-4o-mini` | ~$0.001 | **Recommended.** Cheapest, fastest, reliable |
294
295
  | Gemini | `gemini-2.5-flash` | ~$0.001 | Fast, good accuracy |
295
- | Anthropic | `claude-sonnet-4-5-20250929` | ~$0.005 | High accuracy on constrained generation |
296
- | OpenAI | `gpt-4o` | ~$0.005 | Higher quality, slightly slower |
297
296
  | DeepSeek | `deepseek-chat` | ~$0.001 | Fast, accessible in China |
298
297
  | Qwen | `qwen-plus` | ~$0.002 | Alibaba Cloud, accessible in China |
298
+ | Anthropic | `claude-sonnet-4-5-20250929` | ~$0.005 | Works but slower and more expensive |
299
299
  | Ollama | `llama3.1` | Free (local) | Requires local GPU; variable accuracy |
300
- | Claude Code | `default` | Subscription | **Not recommended for minting.** CLI startup too slow for 20s window |
301
- | Codex | `default` | Subscription | **Not recommended for minting.** CLI startup too slow for 20s window |
302
300
 
303
301
  ### RPC Recommendations
304
302
 
@@ -369,7 +367,7 @@ npx apow-cli mint
369
367
  5. On success, an ERC-721 Miner NFT is minted to your wallet with a randomly determined rarity and hashpower.
370
368
  6. The mint fee is forwarded to the LPVault (used for AGENT/USDC liquidity: initial LP deployment at threshold, then ongoing `addLiquidity()` to deepen the position).
371
369
 
372
- **Challenge expiry:** 20 seconds from `getChallenge` to `mint`. The LLM must solve quickly. Use an API-based provider (openai/anthropic/gemini/deepseek/qwen). Session-based providers (claude-code/codex) are too slow and will fail.
370
+ **Challenge expiry:** 20 seconds from `getChallenge` to `mint`. The LLM must solve quickly. Use a fast, non-thinking model (gpt-4o-mini, gemini-2.5-flash, deepseek-chat).
373
371
 
374
372
  ### Mint Price
375
373
 
@@ -535,6 +533,8 @@ pm2 logs
535
533
 
536
534
  **RPC rate limits:** For 3+ concurrent miners, use a dedicated RPC endpoint (Alchemy, Infura, QuickNode) instead of the default `https://mainnet.base.org`.
537
535
 
536
+ **Want more hash power?** The nonce grinder scales linearly with CPU cores. Rent a high-core-count machine on [vast.ai](https://vast.ai/) to increase throughput. Not required, but effective for competitive mining.
537
+
538
538
  ### Local LLM Setup (Ollama)
539
539
 
540
540
  ```bash
@@ -554,30 +554,6 @@ Ollama runs on `http://127.0.0.1:11434` by default. The miner connects there aut
554
554
 
555
555
  **Trade-off:** Free inference, but local models may have lower accuracy on the constrained SMHL challenges. The miner retries up to 3 times per challenge, but persistent failures will slow mining.
556
556
 
557
- ### Session Mining (Claude Code / Codex)
558
-
559
- Mine using your existing Claude Code or Codex subscription (no API key required):
560
-
561
- ```bash
562
- # In your .env
563
- LLM_PROVIDER=claude-code
564
- # No LLM_API_KEY needed; the miner shells out to your local CLI
565
- ```
566
-
567
- Or with Codex:
568
- ```bash
569
- LLM_PROVIDER=codex
570
- ```
571
-
572
- **How it works:** Instead of calling an LLM API, the miner executes `claude -p` or `codex exec` locally to solve SMHL challenges. This uses whatever model your CLI session defaults to.
573
-
574
- **Requirements:**
575
- - `claude` or `codex` CLI must be installed and authenticated
576
- - The CLI must be available in your PATH
577
- - Your subscription must be active
578
-
579
- **Warning:** Session-based providers (`claude-code`, `codex`) spawn a CLI subprocess for each SMHL challenge. The startup overhead frequently exceeds the 20-second mint challenge window, causing mints to fail with `Expired`. **For minting, always use an API-based provider** (openai, anthropic, gemini, deepseek, or qwen). Session providers may work for the mining loop (which has no time limit per challenge) but are unreliable and not recommended for autonomous operation.
580
-
581
557
  ### Custom RPC Endpoints
582
558
 
583
559
  Set `RPC_URL` in `.env` to any Base-compatible JSON-RPC endpoint. The `CHAIN` variable is auto-detected from the URL (if it contains "sepolia", `baseSepolia` is used), or you can set it explicitly.
@@ -619,7 +595,7 @@ Use the corresponding testnet contract addresses.
619
595
  | `LLM_API_KEY is required for openai.` | Missing API key for cloud provider | Set `LLM_API_KEY` (or provider-specific key like `OPENAI_API_KEY`) in `.env`, or switch to `ollama` |
620
596
  | `Insufficient fee` | Not enough ETH sent with mint | Check `getMintPrice()` and ensure wallet has enough ETH |
621
597
  | `Sold out` | All 10,000 Miner NFTs minted | No more rigs available; buy one on secondary market |
622
- | `Expired` | SMHL challenge expired (>20s) | Switch to an API-based provider (openai/gemini/anthropic/deepseek/qwen). Session providers (claude-code/codex) are too slow for the 20s mint window |
598
+ | `Expired` | SMHL challenge expired (>20s) | Use a faster model (gpt-4o-mini, gemini-2.5-flash). Thinking models are too slow for the 20s mint window |
623
599
  | `Invalid SMHL` | LLM produced an incorrect solution | Retry; if persistent, switch to a more capable model |
624
600
  | `Not your miner` | Token ID not owned by your wallet | Verify `PRIVATE_KEY` matches the NFT owner; check token ID |
625
601
  | `Supply exhausted` | All 18.9M mineable AGENT has been minted | Mining is complete; no more rewards available |
@@ -632,8 +608,6 @@ Use the corresponding testnet contract addresses.
632
608
  | `SMHL solve failed after 3 attempts` | LLM cannot satisfy constraints | Switch to a more capable model (e.g., `gpt-4o` or `claude-sonnet-4-5-20250929`) |
633
609
  | `Fee forward failed` | LPVault rejected the ETH transfer | LPVault may not be set; check contract deployment |
634
610
  | `10 consecutive failures` | Repeated transient errors | Check RPC connectivity, wallet balance, and LLM availability |
635
- | `Claude Code error: ...` | `claude` CLI failed or timed out | Verify `claude` is installed and in PATH; check subscription is active |
636
- | `Codex error: ...` | `codex` CLI failed or timed out | Verify `codex` is installed and in PATH; check subscription is active |
637
611
  | `Timed out waiting for next block (60s)` | RPC not responding or network stalled | Check RPC connectivity; try a different RPC endpoint |
638
612
 
639
613
  ---
@@ -662,10 +636,11 @@ The CLI makes only these network calls:
662
636
 
663
637
  1. **Blockchain RPC** (to user-configured RPC URL, default: `mainnet.base.org`): standard `eth_call`, `eth_sendRawTransaction`, etc.
664
638
  2. **LLM API** (to user-configured provider): sends only word-puzzle prompts for SMHL solving, never wallet data
665
- 3. **Bridge APIs** (only when using `apow fund --solana`):
639
+ 3. **Bridge APIs** (only when using `apow fund`):
666
640
  - **CoinGecko** (`api.coingecko.com`): SOL/ETH price quotes
667
641
  - **deBridge DLN** (`dln.debridge.finance`): bridge order creation and status (direct signing flow)
668
642
  - **Squid Router** (`v2.api.squidrouter.com`): deposit address generation (deposit address flow)
643
+ - **Uniswap V3** (on-chain, Base): ETH/USDC swaps for auto-split
669
644
  - **Solana RPC** (`api.mainnet-beta.solana.com` or custom): balance checks and tx submission
670
645
 
671
646
  No private keys are transmitted to bridge providers. deBridge returns a serialized Solana transaction that is signed locally. Squid generates a deposit address, and the user sends SOL themselves.
@@ -751,6 +726,82 @@ cat package.json | grep -A5 "scripts" # no postinstall hook
751
726
  - **Standard:** ERC-721 Enumerable + ERC-8004 (Agent Registry)
752
727
  - **Max supply:** 10,000
753
728
 
729
+
730
+ ## 14. Dashboard
731
+
732
+ The `apow dashboard` command group provides a real-time web UI for monitoring your entire mining fleet. Zero external dependencies — it serves vanilla HTML/JS directly from the CLI.
733
+
734
+ ### Subcommands
735
+
736
+ | Command | Description |
737
+ |---------|-------------|
738
+ | `apow dashboard start` | Launch the dashboard web UI at `http://localhost:3847`. Auto-opens browser. Press Ctrl+C to stop. |
739
+ | `apow dashboard add <address>` | Add a wallet address to monitor. Validates 0x + 40 hex chars. |
740
+ | `apow dashboard remove <address>` | Remove a wallet address from monitoring. |
741
+ | `apow dashboard scan [dir]` | Auto-detect wallets from `wallet-0x*.txt` files in the given directory (default: CWD). Also scans `rig*/` subdirectories. |
742
+ | `apow dashboard wallets` | List all currently monitored wallet addresses. |
743
+
744
+ ### How It Works
745
+
746
+ - **Wallet storage:** `~/.apow/wallets.json` — a plain JSON array of Ethereum addresses.
747
+ - **Fleet management:** `~/.apow/fleets.json` — optional, defines named groups of wallets from different sources.
748
+ - **Data fetching:** Chunked RPC multicalls (max 30 per batch) with a 25-second TTL cache. Queries ETH balance, AGENT balance, rig ownership, rarity, hashpower, mine count, and earnings for every wallet.
749
+ - **NFT art:** Renders on-chain SVG art for each Mining Rig with rarity-based color coding.
750
+ - **Auto-seed:** On first run, seeds `wallets.json` with the address from your `.env` if configured.
751
+ - **Auto-detect:** `dashboard start` automatically scans CWD for `wallet-0x*.txt` files before launching.
752
+
753
+ ### Fleet Configuration (`~/.apow/fleets.json`)
754
+
755
+ For managing wallets across multiple machines or directories, create `~/.apow/fleets.json`:
756
+
757
+ ```json
758
+ [
759
+ { "name": "Local", "type": "array", "path": "/home/user/.apow/wallets.json" },
760
+ { "name": "Vast.ai Rigs", "type": "rigdirs", "path": "/mnt/mining/rigs" },
761
+ { "name": "Pool Wallets", "type": "walletfiles", "path": "/mnt/mining/wallets" },
762
+ { "name": "Solkek Fleet", "type": "solkek", "path": "/home/user/solkek-config.json" }
763
+ ]
764
+ ```
765
+
766
+ **Fleet types:**
767
+
768
+ | Type | Source Format | Description |
769
+ |------|--------------|-------------|
770
+ | `array` | JSON array of addresses | Simple list: `["0xABC...", "0xDEF..."]` |
771
+ | `solkek` | JSON with `master.address` + `miners[].address` | Solkek fleet manager format |
772
+ | `rigdirs` | Directory containing `rig*/wallet-0x*.txt` | Scan rig subdirectories for wallet files |
773
+ | `walletfiles` | Directory containing `wallet-0x*.txt` | Scan flat directory for wallet files |
774
+
775
+ If `fleets.json` does not exist, the dashboard falls back to `wallets.json` as a single "Main" fleet.
776
+
777
+ ### Example Workflow
778
+
779
+ ```bash
780
+ # 1. Scan a directory with wallet files to populate wallets.json
781
+ npx apow-cli dashboard scan /path/to/mining/dir
782
+
783
+ # 2. Manually add a wallet not found by scan
784
+ npx apow-cli dashboard add 0x1234567890abcdef1234567890abcdef12345678
785
+
786
+ # 3. Verify your wallet list
787
+ npx apow-cli dashboard wallets
788
+
789
+ # 4. Launch the dashboard
790
+ npx apow-cli dashboard start
791
+ # → Opens http://localhost:3847 in your browser
792
+ # → Shows real-time balances, rig stats, earnings, and NFT art
793
+ # → Press Ctrl+C to stop
794
+ ```
795
+
796
+ ### Troubleshooting
797
+
798
+ | Issue | Cause | Fix |
799
+ |-------|-------|-----|
800
+ | "No wallets configured" | Empty `wallets.json` | Run `apow dashboard add <addr>` or `apow dashboard scan .` |
801
+ | Dashboard shows 0 balances | RPC rate limiting | Set a dedicated `RPC_URL` in `.env` (Alchemy recommended) |
802
+ | Browser doesn't open | Headless/SSH environment | Manually open `http://localhost:3847` in a browser |
803
+ | Stale data | 25s cache TTL | Wait for next refresh cycle or restart the dashboard |
804
+
754
805
  ---
755
806
 
756
807
  **Source:** [github.com/Agentoshi/apow-cli](https://github.com/Agentoshi/apow-cli) | **Protocol:** [github.com/Agentoshi/apow-core](https://github.com/Agentoshi/apow-core)