apow-cli 0.7.1 → 0.8.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 +5 -4
- package/README.md +11 -9
- package/dist/config.js +3 -4
- package/dist/dashboard.js +2 -2
- package/dist/errors.js +2 -2
- package/dist/index.js +22 -4
- package/dist/preflight.js +44 -32
- package/dist/x402.js +61 -25
- package/package.json +2 -3
- package/skill.md +5 -4
package/.env.example
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Wallet
|
|
2
2
|
PRIVATE_KEY=
|
|
3
3
|
|
|
4
|
-
# RPC —
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
#
|
|
4
|
+
# RPC — You need one of these two options:
|
|
5
|
+
# Option 1: Bring your own RPC URL (free from Alchemy, QuickNode, etc.)
|
|
6
|
+
RPC_URL=
|
|
7
|
+
# Option 2: Auto-pay via QuickNode x402 ($10 USDC for ~1M calls, no API key needed)
|
|
8
|
+
# USE_X402=true
|
|
8
9
|
|
|
9
10
|
# LLM Provider (openai / anthropic / gemini / ollama / claude-code / codex)
|
|
10
11
|
LLM_PROVIDER=openai
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# APoW CLI
|
|
2
2
|
|
|
3
|
-
Mining client for the [APoW (Agentic Proof of Work)](https://github.com/Agentoshi/apow-core) protocol on Base. Prove
|
|
3
|
+
Mining client for the [APoW (Agentic Proof of Work)](https://github.com/Agentoshi/apow-core) protocol on Base. Prove you're an AI agent once by minting an ERC-721 Mining Rig, then compete on hash power to mine $AGENT tokens.
|
|
4
4
|
|
|
5
5
|
**Your agent does all the work. You just fund a wallet.**
|
|
6
6
|
|
|
@@ -16,13 +16,14 @@ Or run directly:
|
|
|
16
16
|
npx apow-cli
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
## RPC
|
|
19
|
+
## RPC Setup
|
|
20
20
|
|
|
21
|
-
> **v0.
|
|
21
|
+
> **v0.8.0+: Bring your own RPC or use auto-pay.** You need a Base RPC endpoint. Two options:
|
|
22
22
|
>
|
|
23
|
-
> **
|
|
23
|
+
> 1. **Bring your own** (free): Get a free RPC URL from [Alchemy](https://www.alchemy.com/), [QuickNode](https://www.quicknode.com/), or any Base RPC provider. Set `RPC_URL` in your `.env`.
|
|
24
|
+
> 2. **QuickNode x402** (paid, zero setup): Set `USE_X402=true` in your `.env`. Your mining wallet pays $10 USDC for ~1M RPC calls via the [x402 payment protocol](https://www.x402.org/). No API key, no account needed.
|
|
24
25
|
>
|
|
25
|
-
>
|
|
26
|
+
> Run `apow setup` to configure interactively.
|
|
26
27
|
|
|
27
28
|
## For AI Agents
|
|
28
29
|
|
|
@@ -35,7 +36,7 @@ npx apow-cli wallet new
|
|
|
35
36
|
|
|
36
37
|
# 2. Write .env (no interactive prompts)
|
|
37
38
|
# LLM config is only needed for minting; mining uses optimized SMHL solving
|
|
38
|
-
# RPC
|
|
39
|
+
# RPC: set RPC_URL for a free RPC, or USE_X402=true for auto-pay ($10 USDC)
|
|
39
40
|
cat > .env << 'EOF'
|
|
40
41
|
PRIVATE_KEY=0x<from step 1>
|
|
41
42
|
LLM_PROVIDER=openai # Required for minting only
|
|
@@ -47,7 +48,7 @@ EOF
|
|
|
47
48
|
npx apow-cli fund --chain solana --token sol # bridge SOL → ETH+USDC on Base
|
|
48
49
|
# Or send ETH/USDC on Base directly
|
|
49
50
|
|
|
50
|
-
# 4. Mint a mining rig NFT (proves
|
|
51
|
+
# 4. Mint a mining rig NFT (proves AI via LLM, one-time)
|
|
51
52
|
npx apow-cli mint
|
|
52
53
|
|
|
53
54
|
# 5. Start mining (runs forever, no LLM needed, multi-threaded)
|
|
@@ -109,7 +110,8 @@ Create a `.env` file or use `apow setup`:
|
|
|
109
110
|
|
|
110
111
|
```bash
|
|
111
112
|
PRIVATE_KEY=0x... # Your wallet private key
|
|
112
|
-
|
|
113
|
+
RPC_URL=https://... # Your Base RPC URL (free from Alchemy, QuickNode, etc.)
|
|
114
|
+
# USE_X402=true # Or: auto-pay via QuickNode x402 ($10 USDC for ~1M calls)
|
|
113
115
|
LLM_PROVIDER=openai # openai | gemini | deepseek | qwen | anthropic | ollama (for minting)
|
|
114
116
|
LLM_MODEL=gpt-4o-mini # Required for minting only; mining uses optimized SMHL solving
|
|
115
117
|
LLM_API_KEY=sk-... # Required for minting only
|
|
@@ -161,7 +163,7 @@ apow fund --chain base --no-swap
|
|
|
161
163
|
|
|
162
164
|
Mining in v0.4.0 uses two key optimizations:
|
|
163
165
|
|
|
164
|
-
- **Algorithmic SMHL**: Mining SMHL challenges are solved algorithmically in microseconds (no LLM call). Your
|
|
166
|
+
- **Algorithmic SMHL**: Mining SMHL challenges are solved algorithmically in microseconds (no LLM call). Your AI was already proven when you minted your Mining Rig.
|
|
165
167
|
- **Multi-threaded nonce grinding**: Hash computation is parallelized across all CPU cores via `worker_threads`. Set `MINER_THREADS` in `.env` to override the default (all cores).
|
|
166
168
|
|
|
167
169
|
> **Want more hash power?** Rent a high-core-count machine on [vast.ai](https://vast.ai/) to increase your nonce grinding throughput. Not required, but scales linearly with core count.
|
package/dist/config.js
CHANGED
|
@@ -15,7 +15,6 @@ const node_path_1 = require("node:path");
|
|
|
15
15
|
const chains_1 = require("viem/chains");
|
|
16
16
|
(0, dotenv_1.config)();
|
|
17
17
|
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
18
|
-
const DEFAULT_RPC_URL = "https://mainnet.base.org";
|
|
19
18
|
const DEFAULT_LLM_PROVIDER = "openai";
|
|
20
19
|
const DEFAULT_LLM_MODEL = "gpt-4o-mini";
|
|
21
20
|
const DEFAULT_OLLAMA_URL = "http://127.0.0.1:11434";
|
|
@@ -35,7 +34,7 @@ function resolveChainName() {
|
|
|
35
34
|
if (envChain === "base" || envChain === "baseSepolia") {
|
|
36
35
|
return envChain;
|
|
37
36
|
}
|
|
38
|
-
const rpcUrl = process.env.RPC_URL ??
|
|
37
|
+
const rpcUrl = process.env.RPC_URL ?? "";
|
|
39
38
|
if (rpcUrl.toLowerCase().includes("sepolia")) {
|
|
40
39
|
return "baseSepolia";
|
|
41
40
|
}
|
|
@@ -78,8 +77,8 @@ function resolveLlmApiKey(provider) {
|
|
|
78
77
|
const chainName = resolveChainName();
|
|
79
78
|
exports.config = {
|
|
80
79
|
privateKey: parsePrivateKey(process.env.PRIVATE_KEY),
|
|
81
|
-
rpcUrl: process.env.RPC_URL ??
|
|
82
|
-
useX402:
|
|
80
|
+
rpcUrl: process.env.RPC_URL ?? "",
|
|
81
|
+
useX402: process.env.USE_X402 === "true",
|
|
83
82
|
llmProvider: normalizeProvider(process.env.LLM_PROVIDER),
|
|
84
83
|
llmApiKey: resolveLlmApiKey(normalizeProvider(process.env.LLM_PROVIDER)),
|
|
85
84
|
llmModel: process.env.LLM_MODEL ?? DEFAULT_LLM_MODEL,
|
package/dist/dashboard.js
CHANGED
|
@@ -50,7 +50,7 @@ const AgentCoinAbi = AgentCoin_json_1.default;
|
|
|
50
50
|
const MiningAgentAbi = MiningAgent_json_1.default;
|
|
51
51
|
const RARITY_LABELS = ["Common", "Uncommon", "Rare", "Epic", "Mythic"];
|
|
52
52
|
const ADDR_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
53
|
-
const DEFAULT_RPC = "
|
|
53
|
+
const DEFAULT_RPC = ""; // No default public RPC — x402 is the default
|
|
54
54
|
const FLEETS_PATH = (0, node_path_1.join)(process.env.HOME ?? "", ".apow", "fleets.json");
|
|
55
55
|
// --- Wallet / Fleet loading ---
|
|
56
56
|
function isAddress(s) {
|
|
@@ -427,7 +427,7 @@ function startDashboardServer(opts) {
|
|
|
427
427
|
return JSON.stringify(fleets.map((f) => ({ name: f.name, walletCount: f.addresses.length })));
|
|
428
428
|
}
|
|
429
429
|
function handleConfig() {
|
|
430
|
-
const rpcIsDefault = rpcUrl === DEFAULT_RPC;
|
|
430
|
+
const rpcIsDefault = useX402 || rpcUrl === DEFAULT_RPC;
|
|
431
431
|
const walletCount = getWalletAddresses(walletsPath).length;
|
|
432
432
|
return JSON.stringify({ rpcIsDefault, walletCount });
|
|
433
433
|
}
|
package/dist/errors.js
CHANGED
|
@@ -73,8 +73,8 @@ const patterns = [
|
|
|
73
73
|
test: (m) => /\b402\b/.test(m) || m.toLowerCase().includes("x402") || (m.toLowerCase().includes("insufficient") && m.toLowerCase().includes("usdc")),
|
|
74
74
|
classify: () => ({
|
|
75
75
|
category: "transient",
|
|
76
|
-
userMessage: "x402
|
|
77
|
-
recovery: "Send USDC to your wallet on Base, or set RPC_URL in .env to use a
|
|
76
|
+
userMessage: "QuickNode x402 credit purchase failed — check USDC balance on Base",
|
|
77
|
+
recovery: "Send USDC to your wallet on Base (~$10 for ~1M RPC calls), or set RPC_URL in .env to use a custom RPC",
|
|
78
78
|
}),
|
|
79
79
|
},
|
|
80
80
|
{
|
package/dist/index.js
CHANGED
|
@@ -170,10 +170,28 @@ async function setupWizard() {
|
|
|
170
170
|
console.log("");
|
|
171
171
|
// Step 2: RPC
|
|
172
172
|
console.log(` ${ui.bold("Step 2/3: RPC")}`);
|
|
173
|
-
console.log(` ${ui.dim("
|
|
174
|
-
console.log(` ${ui.dim("
|
|
175
|
-
console.log(` ${ui.dim("
|
|
176
|
-
ui.
|
|
173
|
+
console.log(` ${ui.dim("You need a Base RPC endpoint. Two options:")}`);
|
|
174
|
+
console.log(` ${ui.dim(" 1. Bring your own (free from Alchemy, QuickNode, etc.)")}`);
|
|
175
|
+
console.log(` ${ui.dim(" 2. Auto-pay via QuickNode x402 ($10 USDC for ~1M calls)")}`);
|
|
176
|
+
const hasRpc = await ui.confirm("Do you have a Base RPC URL?");
|
|
177
|
+
if (hasRpc) {
|
|
178
|
+
const rpcUrl = await ui.prompt("RPC URL");
|
|
179
|
+
if (rpcUrl) {
|
|
180
|
+
values.RPC_URL = rpcUrl;
|
|
181
|
+
ui.ok(`RPC: Custom (${rpcUrl.slice(0, 40)}${rpcUrl.length > 40 ? "..." : ""})`);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
ui.warn("No URL provided — using QuickNode x402");
|
|
185
|
+
values.USE_X402 = "true";
|
|
186
|
+
ui.ok("RPC: QuickNode x402 ($10 USDC for ~1M calls)");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
values.USE_X402 = "true";
|
|
191
|
+
console.log(` ${ui.dim("QuickNode x402 will charge $10 USDC from your mining wallet")}`);
|
|
192
|
+
console.log(` ${ui.dim("for ~1M RPC calls. No API key or account needed.")}`);
|
|
193
|
+
ui.ok("RPC: QuickNode x402 ($10 USDC for ~1M calls)");
|
|
194
|
+
}
|
|
177
195
|
console.log("");
|
|
178
196
|
// Step 3: LLM (for minting)
|
|
179
197
|
console.log(` ${ui.bold("Step 3/3: LLM Provider (for minting)")}`);
|
package/dist/preflight.js
CHANGED
|
@@ -42,7 +42,6 @@ const chains_1 = require("viem/chains");
|
|
|
42
42
|
const AgentCoin_json_1 = __importDefault(require("./abi/AgentCoin.json"));
|
|
43
43
|
const config_1 = require("./config");
|
|
44
44
|
const wallet_1 = require("./wallet");
|
|
45
|
-
const x402_1 = require("./x402");
|
|
46
45
|
const ui = __importStar(require("./ui"));
|
|
47
46
|
const agentCoinAbi = AgentCoin_json_1.default;
|
|
48
47
|
const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
@@ -70,29 +69,16 @@ async function runPreflight(level) {
|
|
|
70
69
|
else {
|
|
71
70
|
results.push({ label: "Contract addresses configured", passed: true });
|
|
72
71
|
}
|
|
73
|
-
// Check
|
|
74
|
-
|
|
75
|
-
const chainId = await wallet_1.publicClient.getChainId();
|
|
76
|
-
const expectedId = config_1.config.chain.id;
|
|
77
|
-
if (chainId !== expectedId) {
|
|
78
|
-
results.push({
|
|
79
|
-
label: `RPC chain mismatch — expected ${expectedId}, got ${chainId}`,
|
|
80
|
-
passed: false,
|
|
81
|
-
fix: "Update RPC_URL to point to the correct network",
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
results.push({ label: `RPC connected — ${config_1.config.chain.name}`, passed: true });
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
72
|
+
// Check: RPC configured (either RPC_URL or USE_X402)
|
|
73
|
+
if (!config_1.config.useX402 && !config_1.config.rpcUrl) {
|
|
89
74
|
results.push({
|
|
90
|
-
label:
|
|
75
|
+
label: "No RPC configured",
|
|
91
76
|
passed: false,
|
|
92
|
-
fix: "
|
|
77
|
+
fix: "Run `apow setup` to configure RPC, or set RPC_URL or USE_X402=true in .env",
|
|
93
78
|
});
|
|
94
79
|
}
|
|
95
|
-
// Check x402: USDC balance
|
|
80
|
+
// Check x402: USDC balance BEFORE RPC check (can't use x402 without USDC)
|
|
81
|
+
let x402Funded = false;
|
|
96
82
|
if (config_1.config.useX402 && wallet_1.account) {
|
|
97
83
|
try {
|
|
98
84
|
// Use a separate lightweight client to avoid chicken-and-egg
|
|
@@ -108,27 +94,53 @@ async function runPreflight(level) {
|
|
|
108
94
|
args: [wallet_1.account.address],
|
|
109
95
|
}));
|
|
110
96
|
if (usdcBalance === 0n) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
(0, wallet_1.reinitClients)();
|
|
97
|
+
results.push({
|
|
98
|
+
label: "No USDC balance — QuickNode x402 requires USDC on Base",
|
|
99
|
+
passed: false,
|
|
100
|
+
fix: `Send USDC to ${wallet_1.account.address} on Base (~$10 for ~1M RPC calls). Run \`apow fund\` to bridge from Solana.`,
|
|
101
|
+
});
|
|
117
102
|
}
|
|
118
103
|
else {
|
|
104
|
+
x402Funded = true;
|
|
119
105
|
const formatted = (0, viem_1.formatUnits)(usdcBalance, USDC_DECIMALS);
|
|
120
106
|
results.push({
|
|
121
|
-
label: `RPC:
|
|
107
|
+
label: `RPC: QuickNode x402 (${formatted} USDC available)`,
|
|
122
108
|
passed: true,
|
|
123
109
|
});
|
|
124
110
|
}
|
|
125
111
|
}
|
|
126
112
|
catch {
|
|
127
|
-
// USDC check failed —
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
113
|
+
// USDC check failed — can't verify, warn but don't block
|
|
114
|
+
x402Funded = true; // optimistic — let the RPC check determine reachability
|
|
115
|
+
ui.warn("Could not check USDC balance — QuickNode x402 may fail if wallet has no USDC");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Check 2: RPC reachable + chain ID
|
|
119
|
+
// Skip when: no RPC configured at all, or x402 active but unfunded
|
|
120
|
+
const hasRpc = config_1.config.useX402 || !!config_1.config.rpcUrl;
|
|
121
|
+
if (hasRpc && (!config_1.config.useX402 || x402Funded)) {
|
|
122
|
+
try {
|
|
123
|
+
const chainId = await wallet_1.publicClient.getChainId();
|
|
124
|
+
const expectedId = config_1.config.chain.id;
|
|
125
|
+
if (chainId !== expectedId) {
|
|
126
|
+
results.push({
|
|
127
|
+
label: `RPC chain mismatch — expected ${expectedId}, got ${chainId}`,
|
|
128
|
+
passed: false,
|
|
129
|
+
fix: "Update RPC_URL to point to the correct network",
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
results.push({ label: `RPC connected — ${config_1.config.chain.name}`, passed: true });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
results.push({
|
|
138
|
+
label: `RPC unreachable — could not connect to ${config_1.config.useX402 ? "QuickNode x402" : config_1.config.rpcUrl}`,
|
|
139
|
+
passed: false,
|
|
140
|
+
fix: config_1.config.useX402
|
|
141
|
+
? "Check internet connection and USDC balance, or set RPC_URL in .env for a custom RPC"
|
|
142
|
+
: "Check internet connection or update RPC_URL in .env",
|
|
143
|
+
});
|
|
132
144
|
}
|
|
133
145
|
}
|
|
134
146
|
if (level === "wallet" || level === "mining") {
|
package/dist/x402.js
CHANGED
|
@@ -1,45 +1,81 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.createX402Transport = createX402Transport;
|
|
4
37
|
exports.resetX402 = resetX402;
|
|
5
|
-
const accounts_1 = require("viem/accounts");
|
|
6
38
|
const viem_1 = require("viem");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function
|
|
11
|
-
if (
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const client = new x402Client();
|
|
23
|
-
client.register("eip155:*", new ExactEvmScheme(signer));
|
|
24
|
-
_paidFetch = wrapFetchWithPayment(fetch, client);
|
|
25
|
-
return _paidFetch;
|
|
39
|
+
const QUICKNODE_BASE = "https://x402.quicknode.com";
|
|
40
|
+
const BASE_MAINNET = "eip155:8453";
|
|
41
|
+
let _client = null;
|
|
42
|
+
async function getClient(privateKey) {
|
|
43
|
+
if (_client && !_client.isTokenExpired())
|
|
44
|
+
return _client;
|
|
45
|
+
const { createQuicknodeX402Client } = await Promise.resolve().then(() => __importStar(require("@quicknode/x402")));
|
|
46
|
+
_client = await createQuicknodeX402Client({
|
|
47
|
+
baseUrl: QUICKNODE_BASE,
|
|
48
|
+
network: BASE_MAINNET,
|
|
49
|
+
evmPrivateKey: privateKey,
|
|
50
|
+
preAuth: true,
|
|
51
|
+
// paymentModel defaults to 'credit-drawdown' — no per-request payments
|
|
52
|
+
});
|
|
53
|
+
return _client;
|
|
26
54
|
}
|
|
27
55
|
function createX402Transport(privateKey) {
|
|
28
56
|
return (0, viem_1.custom)({
|
|
29
57
|
async request({ method, params }) {
|
|
30
|
-
const
|
|
31
|
-
const response = await
|
|
58
|
+
const client = await getClient(privateKey);
|
|
59
|
+
const response = await client.fetch(`${QUICKNODE_BASE}/base-mainnet`, {
|
|
32
60
|
method: "POST",
|
|
33
61
|
headers: { "Content-Type": "application/json" },
|
|
34
62
|
body: JSON.stringify({ jsonrpc: "2.0", method, params, id: 1 }),
|
|
35
63
|
});
|
|
64
|
+
if (response.status === 402) {
|
|
65
|
+
throw new Error("x402 payment failed — insufficient USDC balance on Base");
|
|
66
|
+
}
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
throw new Error(`QuickNode x402 HTTP ${response.status}: ${response.statusText}`);
|
|
69
|
+
}
|
|
36
70
|
const data = (await response.json());
|
|
37
|
-
if (data.error)
|
|
38
|
-
|
|
71
|
+
if (data.error) {
|
|
72
|
+
const msg = typeof data.error === "string" ? data.error : data.error.message;
|
|
73
|
+
throw new Error(msg);
|
|
74
|
+
}
|
|
39
75
|
return data.result;
|
|
40
76
|
},
|
|
41
77
|
});
|
|
42
78
|
}
|
|
43
79
|
function resetX402() {
|
|
44
|
-
|
|
80
|
+
_client = null;
|
|
45
81
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apow-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Mine AGENT tokens on Base L2 with Agentic Proof of Work",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"apow",
|
|
@@ -39,9 +39,8 @@
|
|
|
39
39
|
"prepublishOnly": "npm run build"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"@quicknode/x402": "^0.1.2",
|
|
42
43
|
"@solana/web3.js": "^1.98.0",
|
|
43
|
-
"@x402/evm": "^2.8.0",
|
|
44
|
-
"@x402/fetch": "^2.8.0",
|
|
45
44
|
"commander": "^14.0.0",
|
|
46
45
|
"dotenv": "^17.2.3",
|
|
47
46
|
"openai": "^6.6.0",
|
package/skill.md
CHANGED
|
@@ -25,7 +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
|
-
> **RPC:**
|
|
28
|
+
> **RPC:** You need a Base RPC endpoint. Either set `RPC_URL` in `.env` (free from Alchemy, QuickNode, etc.) or set `USE_X402=true` to auto-pay via [QuickNode x402](https://x402.quicknode.com/) ($10 USDC for ~1M calls, no API key needed). Run `apow setup` to configure interactively.
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
@@ -93,7 +93,7 @@ SMHL ("Show Me Human Language") serves two different roles in APoW:
|
|
|
93
93
|
|
|
94
94
|
**SMHL for Minting (identity verification):** When minting a Mining Rig, your LLM solves an SMHL challenge to prove agent capability. This is the "prove yourself" gate: your agent demonstrates it can solve constrained text generation. The LLM receives a prompt like: "Generate a sentence that is approximately N characters long, contains approximately W words, and includes the letter 'X'."
|
|
95
95
|
|
|
96
|
-
**SMHL for Mining (algorithmic):** During mining, SMHL solutions are generated algorithmically in microseconds, with no LLM needed. Your
|
|
96
|
+
**SMHL for Mining (algorithmic):** During mining, SMHL solutions are generated algorithmically in microseconds, with no LLM needed. Your AI was already proven when you minted your Mining Rig. Mining is a hash power competition, not a language puzzle.
|
|
97
97
|
|
|
98
98
|
On-chain verification checks (both minting and mining):
|
|
99
99
|
1. **Length** (in bytes): within ±5 of the target
|
|
@@ -263,7 +263,8 @@ CHAIN=base
|
|
|
263
263
|
| `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. |
|
|
264
264
|
| `LLM_MODEL` | For minting | `gpt-4o-mini` | Model identifier passed to the provider (minting only) |
|
|
265
265
|
| `MINER_THREADS` | No | All CPU cores | Number of threads for parallel nonce grinding |
|
|
266
|
-
| `RPC_URL` |
|
|
266
|
+
| `RPC_URL` | Yes* | — | Base JSON-RPC endpoint. Get a free URL from Alchemy or QuickNode. *Not needed if `USE_X402=true`. |
|
|
267
|
+
| `USE_X402` | No | `false` | Set to `true` to auto-pay via QuickNode x402 ($10 USDC for ~1M calls). Replaces `RPC_URL`. |
|
|
267
268
|
| `CHAIN` | No | `base` | Network selector; auto-detects `baseSepolia` if RPC URL contains "sepolia" |
|
|
268
269
|
| `SOLANA_RPC_URL` | No | `https://api.mainnet-beta.solana.com` | Solana RPC endpoint (only for `apow fund --chain solana`) |
|
|
269
270
|
| `SQUID_INTEGRATOR_ID` | No | - | Squid Router integrator ID for deposit address flow (free at [squidrouter.com](https://app.squidrouter.com/)) |
|
|
@@ -545,7 +546,7 @@ Set `RPC_URL` in `.env` to any Base-compatible JSON-RPC endpoint. The `CHAIN` va
|
|
|
545
546
|
|
|
546
547
|
### Agent Wallet
|
|
547
548
|
|
|
548
|
-
Each Miner NFT supports an on-chain agent wallet. This creates a one-rig-one-agent
|
|
549
|
+
Each Miner NFT supports an on-chain agent wallet. This creates a one-rig-one-agent model: an NFT owner can delegate mining operations to a separate hot wallet without transferring ownership of the rig.
|
|
549
550
|
|
|
550
551
|
**Functions:**
|
|
551
552
|
- `getAgentWallet(tokenId)`: returns the registered agent wallet address
|