apow-cli 0.4.1 → 0.6.0
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/.env.example +9 -4
- package/README.md +83 -20
- package/dist/bridge/constants.js +34 -0
- package/dist/bridge/debridge.js +151 -28
- package/dist/bridge/solana.js +13 -0
- package/dist/bridge/squid.js +54 -21
- package/dist/bridge/uniswap.js +184 -0
- package/dist/config.js +1 -0
- package/dist/dashboard.js +6 -2
- package/dist/errors.js +40 -0
- package/dist/fund.js +506 -133
- package/dist/index.js +10 -23
- package/dist/preflight.js +52 -0
- package/dist/wallet.js +24 -2
- package/dist/x402.js +45 -0
- package/package.json +3 -1
- package/skill.md +87 -38
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
|
281
|
-
.option("--
|
|
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
|
|
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
|
|
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.
|
|
3
|
+
"version": "0.6.0",
|
|
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
|
@@ -117,7 +117,7 @@ The miner client validates locally before submitting.
|
|
|
117
117
|
|---|---|
|
|
118
118
|
| **Node.js** | v18 or higher |
|
|
119
119
|
| **Base wallet** | A private key with ETH on Base (for gas + mint fee) |
|
|
120
|
-
| **LLM access** | API key (OpenAI,
|
|
120
|
+
| **LLM access** | API key (OpenAI, Gemini, DeepSeek, Qwen, or Anthropic) or local Ollama (**required for minting only**) |
|
|
121
121
|
| **git** | Only if installing from source (not needed for npm) |
|
|
122
122
|
|
|
123
123
|
---
|
|
@@ -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" | "
|
|
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,8 +273,8 @@ 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`, `
|
|
277
|
-
| `LLM_API_KEY` | For minting | - | API key for minting. Falls back to `OPENAI_API_KEY` / `
|
|
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
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.** |
|
|
@@ -286,19 +286,16 @@ CHAIN=base
|
|
|
286
286
|
|
|
287
287
|
> 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
288
|
>
|
|
289
|
-
>
|
|
289
|
+
> 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
290
|
|
|
291
291
|
| Provider | Model | Cost per call | Notes |
|
|
292
292
|
|---|---|---|---|
|
|
293
|
-
| OpenAI | `gpt-4o-mini` | ~$0.001 | **Recommended
|
|
293
|
+
| OpenAI | `gpt-4o-mini` | ~$0.001 | **Recommended.** Cheapest, fastest, reliable |
|
|
294
294
|
| 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
295
|
| DeepSeek | `deepseek-chat` | ~$0.001 | Fast, accessible in China |
|
|
298
296
|
| Qwen | `qwen-plus` | ~$0.002 | Alibaba Cloud, accessible in China |
|
|
297
|
+
| Anthropic | `claude-sonnet-4-5-20250929` | ~$0.005 | Works but slower and more expensive |
|
|
299
298
|
| 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
299
|
|
|
303
300
|
### RPC Recommendations
|
|
304
301
|
|
|
@@ -369,7 +366,7 @@ npx apow-cli mint
|
|
|
369
366
|
5. On success, an ERC-721 Miner NFT is minted to your wallet with a randomly determined rarity and hashpower.
|
|
370
367
|
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
368
|
|
|
372
|
-
**Challenge expiry:** 20 seconds from `getChallenge` to `mint`. The LLM must solve quickly. Use
|
|
369
|
+
**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
370
|
|
|
374
371
|
### Mint Price
|
|
375
372
|
|
|
@@ -535,6 +532,8 @@ pm2 logs
|
|
|
535
532
|
|
|
536
533
|
**RPC rate limits:** For 3+ concurrent miners, use a dedicated RPC endpoint (Alchemy, Infura, QuickNode) instead of the default `https://mainnet.base.org`.
|
|
537
534
|
|
|
535
|
+
**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.
|
|
536
|
+
|
|
538
537
|
### Local LLM Setup (Ollama)
|
|
539
538
|
|
|
540
539
|
```bash
|
|
@@ -554,30 +553,6 @@ Ollama runs on `http://127.0.0.1:11434` by default. The miner connects there aut
|
|
|
554
553
|
|
|
555
554
|
**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
555
|
|
|
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
556
|
### Custom RPC Endpoints
|
|
582
557
|
|
|
583
558
|
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 +594,7 @@ Use the corresponding testnet contract addresses.
|
|
|
619
594
|
| `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
595
|
| `Insufficient fee` | Not enough ETH sent with mint | Check `getMintPrice()` and ensure wallet has enough ETH |
|
|
621
596
|
| `Sold out` | All 10,000 Miner NFTs minted | No more rigs available; buy one on secondary market |
|
|
622
|
-
| `Expired` | SMHL challenge expired (>20s) |
|
|
597
|
+
| `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
598
|
| `Invalid SMHL` | LLM produced an incorrect solution | Retry; if persistent, switch to a more capable model |
|
|
624
599
|
| `Not your miner` | Token ID not owned by your wallet | Verify `PRIVATE_KEY` matches the NFT owner; check token ID |
|
|
625
600
|
| `Supply exhausted` | All 18.9M mineable AGENT has been minted | Mining is complete; no more rewards available |
|
|
@@ -632,8 +607,6 @@ Use the corresponding testnet contract addresses.
|
|
|
632
607
|
| `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
608
|
| `Fee forward failed` | LPVault rejected the ETH transfer | LPVault may not be set; check contract deployment |
|
|
634
609
|
| `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
610
|
| `Timed out waiting for next block (60s)` | RPC not responding or network stalled | Check RPC connectivity; try a different RPC endpoint |
|
|
638
611
|
|
|
639
612
|
---
|
|
@@ -751,6 +724,82 @@ cat package.json | grep -A5 "scripts" # no postinstall hook
|
|
|
751
724
|
- **Standard:** ERC-721 Enumerable + ERC-8004 (Agent Registry)
|
|
752
725
|
- **Max supply:** 10,000
|
|
753
726
|
|
|
727
|
+
|
|
728
|
+
## 14. Dashboard
|
|
729
|
+
|
|
730
|
+
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.
|
|
731
|
+
|
|
732
|
+
### Subcommands
|
|
733
|
+
|
|
734
|
+
| Command | Description |
|
|
735
|
+
|---------|-------------|
|
|
736
|
+
| `apow dashboard start` | Launch the dashboard web UI at `http://localhost:3847`. Auto-opens browser. Press Ctrl+C to stop. |
|
|
737
|
+
| `apow dashboard add <address>` | Add a wallet address to monitor. Validates 0x + 40 hex chars. |
|
|
738
|
+
| `apow dashboard remove <address>` | Remove a wallet address from monitoring. |
|
|
739
|
+
| `apow dashboard scan [dir]` | Auto-detect wallets from `wallet-0x*.txt` files in the given directory (default: CWD). Also scans `rig*/` subdirectories. |
|
|
740
|
+
| `apow dashboard wallets` | List all currently monitored wallet addresses. |
|
|
741
|
+
|
|
742
|
+
### How It Works
|
|
743
|
+
|
|
744
|
+
- **Wallet storage:** `~/.apow/wallets.json` — a plain JSON array of Ethereum addresses.
|
|
745
|
+
- **Fleet management:** `~/.apow/fleets.json` — optional, defines named groups of wallets from different sources.
|
|
746
|
+
- **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.
|
|
747
|
+
- **NFT art:** Renders on-chain SVG art for each Mining Rig with rarity-based color coding.
|
|
748
|
+
- **Auto-seed:** On first run, seeds `wallets.json` with the address from your `.env` if configured.
|
|
749
|
+
- **Auto-detect:** `dashboard start` automatically scans CWD for `wallet-0x*.txt` files before launching.
|
|
750
|
+
|
|
751
|
+
### Fleet Configuration (`~/.apow/fleets.json`)
|
|
752
|
+
|
|
753
|
+
For managing wallets across multiple machines or directories, create `~/.apow/fleets.json`:
|
|
754
|
+
|
|
755
|
+
```json
|
|
756
|
+
[
|
|
757
|
+
{ "name": "Local", "type": "array", "path": "/home/user/.apow/wallets.json" },
|
|
758
|
+
{ "name": "Vast.ai Rigs", "type": "rigdirs", "path": "/mnt/mining/rigs" },
|
|
759
|
+
{ "name": "Pool Wallets", "type": "walletfiles", "path": "/mnt/mining/wallets" },
|
|
760
|
+
{ "name": "Solkek Fleet", "type": "solkek", "path": "/home/user/solkek-config.json" }
|
|
761
|
+
]
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
**Fleet types:**
|
|
765
|
+
|
|
766
|
+
| Type | Source Format | Description |
|
|
767
|
+
|------|--------------|-------------|
|
|
768
|
+
| `array` | JSON array of addresses | Simple list: `["0xABC...", "0xDEF..."]` |
|
|
769
|
+
| `solkek` | JSON with `master.address` + `miners[].address` | Solkek fleet manager format |
|
|
770
|
+
| `rigdirs` | Directory containing `rig*/wallet-0x*.txt` | Scan rig subdirectories for wallet files |
|
|
771
|
+
| `walletfiles` | Directory containing `wallet-0x*.txt` | Scan flat directory for wallet files |
|
|
772
|
+
|
|
773
|
+
If `fleets.json` does not exist, the dashboard falls back to `wallets.json` as a single "Main" fleet.
|
|
774
|
+
|
|
775
|
+
### Example Workflow
|
|
776
|
+
|
|
777
|
+
```bash
|
|
778
|
+
# 1. Scan a directory with wallet files to populate wallets.json
|
|
779
|
+
npx apow-cli dashboard scan /path/to/mining/dir
|
|
780
|
+
|
|
781
|
+
# 2. Manually add a wallet not found by scan
|
|
782
|
+
npx apow-cli dashboard add 0x1234567890abcdef1234567890abcdef12345678
|
|
783
|
+
|
|
784
|
+
# 3. Verify your wallet list
|
|
785
|
+
npx apow-cli dashboard wallets
|
|
786
|
+
|
|
787
|
+
# 4. Launch the dashboard
|
|
788
|
+
npx apow-cli dashboard start
|
|
789
|
+
# → Opens http://localhost:3847 in your browser
|
|
790
|
+
# → Shows real-time balances, rig stats, earnings, and NFT art
|
|
791
|
+
# → Press Ctrl+C to stop
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
### Troubleshooting
|
|
795
|
+
|
|
796
|
+
| Issue | Cause | Fix |
|
|
797
|
+
|-------|-------|-----|
|
|
798
|
+
| "No wallets configured" | Empty `wallets.json` | Run `apow dashboard add <addr>` or `apow dashboard scan .` |
|
|
799
|
+
| Dashboard shows 0 balances | RPC rate limiting | Set a dedicated `RPC_URL` in `.env` (Alchemy recommended) |
|
|
800
|
+
| Browser doesn't open | Headless/SSH environment | Manually open `http://localhost:3847` in a browser |
|
|
801
|
+
| Stale data | 25s cache TTL | Wait for next refresh cycle or restart the dashboard |
|
|
802
|
+
|
|
754
803
|
---
|
|
755
804
|
|
|
756
805
|
**Source:** [github.com/Agentoshi/apow-cli](https://github.com/Agentoshi/apow-cli) | **Protocol:** [github.com/Agentoshi/apow-core](https://github.com/Agentoshi/apow-core)
|