apow-cli 0.1.2 → 0.1.4
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/miner.js +9 -11
- package/dist/mint.js +23 -45
- package/dist/smhl.js +4 -4
- package/package.json +1 -1
- package/skill.md +12 -8
package/dist/miner.js
CHANGED
|
@@ -265,21 +265,19 @@ async function startMining(tokenId) {
|
|
|
265
265
|
throw new Error("Mine transaction reverted on-chain");
|
|
266
266
|
}
|
|
267
267
|
txSpinner.stop("Submitting transaction... confirmed");
|
|
268
|
-
// Fetch post-mine
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
abi: agentCoinAbi,
|
|
273
|
-
functionName: "tokenMineCount",
|
|
274
|
-
args: [tokenId],
|
|
275
|
-
}),
|
|
276
|
-
wallet_1.publicClient.readContract({
|
|
268
|
+
// Fetch post-mine earnings with retry (public RPC may lag)
|
|
269
|
+
let earnings = runningTotal;
|
|
270
|
+
for (let retry = 0; retry < 5; retry++) {
|
|
271
|
+
earnings = (await wallet_1.publicClient.readContract({
|
|
277
272
|
address: config_1.config.agentCoinAddress,
|
|
278
273
|
abi: agentCoinAbi,
|
|
279
274
|
functionName: "tokenEarnings",
|
|
280
275
|
args: [tokenId],
|
|
281
|
-
})
|
|
282
|
-
|
|
276
|
+
}));
|
|
277
|
+
if (earnings > runningTotal)
|
|
278
|
+
break;
|
|
279
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
280
|
+
}
|
|
283
281
|
const delta = earnings - runningTotal;
|
|
284
282
|
runningTotal = earnings;
|
|
285
283
|
console.log(` ${ui.green("+")} ${(0, viem_1.formatEther)(delta)} AGENT | Total: ${(0, viem_1.formatEther)(earnings)} AGENT | Tx: ${ui.dim((0, explorer_1.txUrl)(txHash))}`);
|
package/dist/mint.js
CHANGED
|
@@ -72,33 +72,6 @@ function deriveChallengeFromSeed(seed) {
|
|
|
72
72
|
totalLength,
|
|
73
73
|
]);
|
|
74
74
|
}
|
|
75
|
-
async function findMintedTokenId(startTokenId, endTokenIdExclusive, owner, blockNumber) {
|
|
76
|
-
for (let tokenId = startTokenId; tokenId < endTokenIdExclusive; tokenId += 1n) {
|
|
77
|
-
try {
|
|
78
|
-
const [tokenOwner, mintBlock] = await Promise.all([
|
|
79
|
-
wallet_1.publicClient.readContract({
|
|
80
|
-
address: config_1.config.miningAgentAddress,
|
|
81
|
-
abi: miningAgentAbi,
|
|
82
|
-
functionName: "ownerOf",
|
|
83
|
-
args: [tokenId],
|
|
84
|
-
}),
|
|
85
|
-
wallet_1.publicClient.readContract({
|
|
86
|
-
address: config_1.config.miningAgentAddress,
|
|
87
|
-
abi: miningAgentAbi,
|
|
88
|
-
functionName: "mintBlock",
|
|
89
|
-
args: [tokenId],
|
|
90
|
-
}),
|
|
91
|
-
]);
|
|
92
|
-
if (tokenOwner.toLowerCase() === owner.toLowerCase() && mintBlock === blockNumber) {
|
|
93
|
-
return tokenId;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
// Ignore missing token ids while scanning the minted window.
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
throw new Error("Unable to determine minted token ID from post-mint contract state.");
|
|
101
|
-
}
|
|
102
75
|
async function runMintFlow() {
|
|
103
76
|
const { account, walletClient } = (0, wallet_1.requireWallet)();
|
|
104
77
|
console.log("");
|
|
@@ -184,14 +157,21 @@ async function runMintFlow() {
|
|
|
184
157
|
throw new Error("Challenge request reverted on-chain");
|
|
185
158
|
}
|
|
186
159
|
challengeSpinner.stop("Requesting challenge... done");
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
160
|
+
// Read challenge seed with retry (public RPC may lag behind tx confirmation)
|
|
161
|
+
let challengeSeed = ZERO_SEED;
|
|
162
|
+
for (let retry = 0; retry < 5; retry++) {
|
|
163
|
+
challengeSeed = (await wallet_1.publicClient.readContract({
|
|
164
|
+
address: config_1.config.miningAgentAddress,
|
|
165
|
+
abi: miningAgentAbi,
|
|
166
|
+
functionName: "challengeSeeds",
|
|
167
|
+
args: [account.address],
|
|
168
|
+
}));
|
|
169
|
+
if (challengeSeed.toLowerCase() !== ZERO_SEED.toLowerCase())
|
|
170
|
+
break;
|
|
171
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
172
|
+
}
|
|
193
173
|
if (challengeSeed.toLowerCase() === ZERO_SEED.toLowerCase()) {
|
|
194
|
-
throw new Error("Challenge seed
|
|
174
|
+
throw new Error("Challenge seed not found after 5 retries. The RPC may be lagging — try again.");
|
|
195
175
|
}
|
|
196
176
|
// Solve SMHL
|
|
197
177
|
const challenge = deriveChallengeFromSeed(challengeSeed);
|
|
@@ -200,11 +180,6 @@ async function runMintFlow() {
|
|
|
200
180
|
smhlSpinner.update(`Solving SMHL... attempt ${attempt}/5`);
|
|
201
181
|
});
|
|
202
182
|
smhlSpinner.stop("Solving SMHL... done");
|
|
203
|
-
const nextTokenIdBefore = (await wallet_1.publicClient.readContract({
|
|
204
|
-
address: config_1.config.miningAgentAddress,
|
|
205
|
-
abi: miningAgentAbi,
|
|
206
|
-
functionName: "nextTokenId",
|
|
207
|
-
}));
|
|
208
183
|
// Mint
|
|
209
184
|
const mintSpinner = ui.spinner("Minting...");
|
|
210
185
|
const mintTx = await walletClient.writeContract({
|
|
@@ -221,12 +196,15 @@ async function runMintFlow() {
|
|
|
221
196
|
throw new Error("Mint transaction reverted on-chain");
|
|
222
197
|
}
|
|
223
198
|
mintSpinner.stop("Minting... confirmed");
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
199
|
+
// Parse token ID from Transfer event in receipt (avoids stale RPC reads)
|
|
200
|
+
const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
201
|
+
const mintLog = receipt.logs.find((log) => log.address.toLowerCase() === config_1.config.miningAgentAddress.toLowerCase() &&
|
|
202
|
+
log.topics[0] === TRANSFER_TOPIC &&
|
|
203
|
+
log.topics[1] === "0x0000000000000000000000000000000000000000000000000000000000000000");
|
|
204
|
+
if (!mintLog || !mintLog.topics[3]) {
|
|
205
|
+
throw new Error("Mint tx confirmed but Transfer event not found in logs. Check tx on Basescan.");
|
|
206
|
+
}
|
|
207
|
+
const tokenId = BigInt(mintLog.topics[3]);
|
|
230
208
|
const [rarityRaw, hashpowerRaw] = await Promise.all([
|
|
231
209
|
wallet_1.publicClient.readContract({
|
|
232
210
|
address: config_1.config.miningAgentAddress,
|
package/dist/smhl.js
CHANGED
|
@@ -59,8 +59,8 @@ function validateSmhlSolution(solution, challenge) {
|
|
|
59
59
|
return issues;
|
|
60
60
|
}
|
|
61
61
|
const len = Buffer.byteLength(solution, "utf8");
|
|
62
|
-
if (Math.abs(len - challenge.totalLength) >
|
|
63
|
-
issues.push(`length ${len} not within ±
|
|
62
|
+
if (Math.abs(len - challenge.totalLength) > 4) {
|
|
63
|
+
issues.push(`length ${len} not within ±4 of ${challenge.totalLength}`);
|
|
64
64
|
}
|
|
65
65
|
if (!/^[\x20-\x7E]+$/.test(solution)) {
|
|
66
66
|
issues.push("solution must use printable ASCII only");
|
|
@@ -82,8 +82,8 @@ function validateSmhlSolution(solution, challenge) {
|
|
|
82
82
|
*/
|
|
83
83
|
function adjustSolution(raw, challenge) {
|
|
84
84
|
const requiredChar = String.fromCharCode(challenge.charValue);
|
|
85
|
-
const minLen = challenge.totalLength -
|
|
86
|
-
const maxLen = challenge.totalLength +
|
|
85
|
+
const minLen = challenge.totalLength - 4;
|
|
86
|
+
const maxLen = challenge.totalLength + 4;
|
|
87
87
|
const maxWords = challenge.wordCount + 2;
|
|
88
88
|
// Clean: lowercase, letters and spaces only, collapse whitespace
|
|
89
89
|
let words = raw
|
package/package.json
CHANGED
package/skill.md
CHANGED
|
@@ -53,6 +53,8 @@ npx apow-cli wallet new
|
|
|
53
53
|
# Captures address + private key from output (also saved to wallet-<address>.txt)
|
|
54
54
|
|
|
55
55
|
# 2. Write .env directly (no interactive prompts needed)
|
|
56
|
+
# IMPORTANT: Use an API-based provider (openai/anthropic/gemini), NOT claude-code/codex.
|
|
57
|
+
# Session-based providers are too slow for the 20-second mint challenge window.
|
|
56
58
|
cat > .env << 'EOF'
|
|
57
59
|
PRIVATE_KEY=0x<from step 1>
|
|
58
60
|
RPC_URL=https://mainnet.base.org
|
|
@@ -237,15 +239,17 @@ CHAIN=base
|
|
|
237
239
|
|
|
238
240
|
### LLM Provider Recommendations
|
|
239
241
|
|
|
242
|
+
> **For AI agents:** Always use an API-based provider (OpenAI, Anthropic, or Gemini). Session-based providers (`claude-code`, `codex`) spawn a CLI subprocess to solve challenges and are too slow to reliably complete the 20-second mint window. They may work for mining (which has no time limit) but will frequently fail during minting.
|
|
243
|
+
|
|
240
244
|
| Provider | Model | Cost per call | Notes |
|
|
241
245
|
|---|---|---|---|
|
|
242
|
-
| OpenAI | `gpt-4o-mini` | ~$0.001 | Cheapest
|
|
243
|
-
|
|
|
246
|
+
| OpenAI | `gpt-4o-mini` | ~$0.001 | **Recommended for agents.** Cheapest, fastest, reliable |
|
|
247
|
+
| Gemini | `gemini-2.5-flash` | ~$0.001 | Fast, good accuracy |
|
|
244
248
|
| Anthropic | `claude-sonnet-4-5-20250929` | ~$0.005 | High accuracy on constrained generation |
|
|
249
|
+
| OpenAI | `gpt-4o` | ~$0.005 | Higher quality, slightly slower |
|
|
245
250
|
| Ollama | `llama3.1` | Free (local) | Requires local GPU; variable accuracy |
|
|
246
|
-
|
|
|
247
|
-
|
|
|
248
|
-
| Codex | `default` | Subscription | Use your existing Codex session — no API key needed |
|
|
251
|
+
| Claude Code | `default` | Subscription | **Not recommended for minting** — CLI startup too slow for 20s window |
|
|
252
|
+
| Codex | `default` | Subscription | **Not recommended for minting** — CLI startup too slow for 20s window |
|
|
249
253
|
|
|
250
254
|
### RPC Recommendations
|
|
251
255
|
|
|
@@ -272,7 +276,7 @@ npx apow-cli mint
|
|
|
272
276
|
5. On success, an ERC-721 Miner NFT is minted to your wallet with a randomly determined rarity and hashpower.
|
|
273
277
|
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).
|
|
274
278
|
|
|
275
|
-
**Challenge expiry:** 20 seconds from `getChallenge` to `mint`. The LLM must solve quickly.
|
|
279
|
+
**Challenge expiry:** 20 seconds from `getChallenge` to `mint`. The LLM must solve quickly. Use an API-based provider (openai/anthropic/gemini) — session-based providers (claude-code/codex) are too slow and will fail.
|
|
276
280
|
|
|
277
281
|
### Mint Price
|
|
278
282
|
|
|
@@ -479,7 +483,7 @@ LLM_PROVIDER=codex
|
|
|
479
483
|
- The CLI must be available in your PATH
|
|
480
484
|
- Your subscription must be active
|
|
481
485
|
|
|
482
|
-
**
|
|
486
|
+
**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, or gemini). Session providers may work for the mining loop (which has no time limit per challenge) but are unreliable and not recommended for autonomous operation.
|
|
483
487
|
|
|
484
488
|
### Custom RPC Endpoints
|
|
485
489
|
|
|
@@ -522,7 +526,7 @@ Use the corresponding testnet contract addresses.
|
|
|
522
526
|
| `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` |
|
|
523
527
|
| `Insufficient fee` | Not enough ETH sent with mint | Check `getMintPrice()` and ensure wallet has enough ETH |
|
|
524
528
|
| `Sold out` | All 10,000 Miner NFTs minted | No more rigs available; buy one on secondary market |
|
|
525
|
-
| `Expired` | SMHL challenge expired (>20s) |
|
|
529
|
+
| `Expired` | SMHL challenge expired (>20s) | Switch to an API-based provider (openai/gemini/anthropic). Session providers (claude-code/codex) are too slow for the 20s mint window |
|
|
526
530
|
| `Invalid SMHL` | LLM produced an incorrect solution | Retry; if persistent, switch to a more capable model |
|
|
527
531
|
| `Not your miner` | Token ID not owned by your wallet | Verify `PRIVATE_KEY` matches the NFT owner; check token ID |
|
|
528
532
|
| `Supply exhausted` | All 18.9M mineable AGENT has been minted | Mining is complete; no more rewards available |
|