clawminer-skill 1.0.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 ADDED
@@ -0,0 +1,19 @@
1
+ # ================================================
2
+ # ClawMiner Skill - Environment Configuration
3
+ # ================================================
4
+ # Copy this file to .env and fill in your values:
5
+ # cp .env.example .env
6
+ # ================================================
7
+
8
+ # [REQUIRED] Your wallet private key (with 0x prefix)
9
+ # ⚠️ Use a dedicated mining wallet, NOT your main wallet!
10
+ PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE
11
+
12
+ # [OPTIONAL] RPC URL (defaults to BSC Testnet public node)
13
+ RPC_URL=https://bsc-testnet.publicnode.com
14
+
15
+ # [OPTIONAL] Contract address (defaults to BSC Testnet deployment)
16
+ CONTRACT_ADDRESS=0xCe9eAa062Ca1F6a8817f229921Ec79ac20705c38
17
+
18
+ # [OPTIONAL] Network: testnet or mainnet
19
+ NETWORK=testnet
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ClawMiner-Project
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # 🦞 ClawMiner Skill
2
+
3
+ > Automated PoW mining for **ClawMiner ($CLAWMINER)** on BSC.
4
+
5
+ ClawMiner is a fully decentralized, Bitcoin-inspired PoW token on Binance Smart Chain. No admin, no pre-mine, non-upgradeable. Mine it with pure computation.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ # Initialize (install + configure wallet)
11
+ npx clawminer-skill init
12
+
13
+ # Start continuous mining
14
+ npx clawminer-skill loop
15
+ ```
16
+
17
+ ## Commands
18
+
19
+ | Command | Description |
20
+ |---------|-------------|
21
+ | `npx clawminer-skill init` | 初始化(安装依赖 + 配置钱包) |
22
+ | `npx clawminer-skill mine` | 单次挖矿 |
23
+ | `npx clawminer-skill loop` | 连续挖矿 24/7(推荐) |
24
+ | `npx clawminer-skill status` | 查看挖矿状态 |
25
+ | `npx clawminer-skill dry-run` | 模拟挖矿(不提交交易) |
26
+
27
+ ## Tokenomics
28
+
29
+ | Parameter | Value |
30
+ |-----------|-------|
31
+ | Total Supply | 21,000,000 CLAWMINER |
32
+ | Initial Reward | 100 CLAWMINER / mine |
33
+ | Halving Cycle | Every 2,100,000 tokens |
34
+ | Max Halvings | 8 |
35
+ | Cooldown | 5 minutes |
36
+ | Difficulty | Starts at 1 byte, increases every 2,000 mines |
37
+
38
+ ## Security
39
+
40
+ - ⚠️ **Use a dedicated mining wallet** — Never use your main wallet
41
+ - 🔒 **Private key stays local** — Stored in `.env`, never committed to git
42
+ - 🛡️ **Contract is immutable** — No admin functions, cannot be modified
43
+
44
+ ## Network
45
+
46
+ Configure via `npx clawminer-skill init`:
47
+
48
+ | Network | Status |
49
+ |---------|--------|
50
+ | BSC Testnet | ✅ Available |
51
+ | BSC Mainnet | ⏳ Coming soon |
52
+
53
+ ## Links
54
+
55
+ - 🌐 Website: [clawminer.xyz](https://clawminer.xyz) *(coming soon)*
56
+ - 📄 Contract (Testnet): [`0xCe9eAa062Ca1F6a8817f229921Ec79ac20705c38`](https://testnet.bscscan.com/address/0xCe9eAa062Ca1F6a8817f229921Ec79ac20705c38)
57
+
58
+ ## License
59
+
60
+ MIT
package/SKILL.md ADDED
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: clawminer
3
+ description: PoW mining skill for ClawMiner ($CLAWMINER) on BSC — auto PoW, auto submit, auto retry
4
+ ---
5
+
6
+ # ClawMiner Mining Skill
7
+
8
+ You are operating the ClawMiner PoW mining skill. This skill allows the user to mine $CLAWMINER tokens on BNB Smart Chain (BSC) through Proof of Work computation.
9
+
10
+ ## Available Commands
11
+
12
+ | Command | What it does |
13
+ |---------|-------------|
14
+ | `npx clawminer-skill init` | 初始化:安装依赖 + 交互式配置钱包 |
15
+ | `npx clawminer-skill mine` | 单次挖矿 |
16
+ | `npx clawminer-skill loop` | 连续挖矿 24/7(推荐)|
17
+ | `npx clawminer-skill status` | 查看挖矿状态 |
18
+ | `npx clawminer-skill dry-run` | 模拟挖矿(不提交交易)|
19
+
20
+ ## Workflow
21
+
22
+ ### Step 1: Install & Initialize
23
+
24
+ Run the init command. It will install dependencies and guide wallet configuration interactively:
25
+
26
+ ```bash
27
+ npx clawminer-skill init
28
+ ```
29
+
30
+ The init process will:
31
+ 1. Install npm dependencies (ethers.js, dotenv)
32
+ 2. Display a **security warning** about using a dedicated mining wallet
33
+ 3. Ask for the user's **private key** (must be a dedicated mining wallet, NOT their main wallet)
34
+ 4. Ask which network (testnet/mainnet)
35
+ 5. Create `.env` configuration file
36
+
37
+ ### Step 2: Start Mining
38
+
39
+ After init is complete, start mining:
40
+
41
+ ```bash
42
+ # Recommended: continuous mining loop
43
+ npx clawminer-skill loop
44
+
45
+ # Or single mine attempt
46
+ npx clawminer-skill mine
47
+ ```
48
+
49
+ ### Step 3: Monitor
50
+
51
+ Check mining status anytime:
52
+
53
+ ```bash
54
+ npx clawminer-skill status
55
+ ```
56
+
57
+ ## ⚠️ Critical Security Rules
58
+
59
+ When the user asks to configure or initialize this skill, you MUST:
60
+
61
+ 1. **WARN** them to use a **dedicated mining wallet**, NOT their main wallet
62
+ 2. **EXPLAIN** that the mining wallet only needs a small amount of BNB for gas fees (~0.001 BNB per mine)
63
+ 3. **SUGGEST** creating a new account in MetaMask specifically for mining
64
+ 4. **NEVER** store or log the private key anywhere other than the local `.env` file
65
+ 5. **NEVER** transmit the private key over any network or API
66
+
67
+ ## Mining Mechanics
68
+
69
+ - Each mine requires computing a PoW proof (hash with N leading zeros)
70
+ - Current difficulty: starts at 1 byte (2 hex chars), increases every 2,000 mines
71
+ - Reward: starts at 100 CLAWMINER per mine, halves every 2,100,000 tokens
72
+ - Cooldown: 5 minutes between mines
73
+ - Gas: ~0.001 BNB per mine transaction on BSC
74
+
75
+ ## Troubleshooting
76
+
77
+ | Issue | Solution |
78
+ |-------|----------|
79
+ | "Cooldown active" | Normal. Wait 5 minutes between mines. Loop mode handles this automatically. |
80
+ | "Proof already used" | The script will auto-retry with a new proof. |
81
+ | Gas estimation failed | Network congestion. The script uses a default gas limit as fallback. |
82
+ | "PRIVATE_KEY not set" | Run `npx clawminer-skill init` first. |
83
+
84
+ ## Contract Info
85
+
86
+ - Token: Claw Miner ($CLAWMINER)
87
+ - Total Supply: 21,000,000
88
+ - Network: BSC Testnet (Chain ID: 97) / BSC Mainnet (Chain ID: 56)
89
+ - Testnet Contract: `0xCe9eAa062Ca1F6a8817f229921Ec79ac20705c38`
package/bin/cli.js ADDED
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * ClawMiner Skill CLI
5
+ *
6
+ * Usage:
7
+ * npx clawminer-skill init # 初始化 Skill(安装依赖 + 引导配置)
8
+ * npx clawminer-skill mine # 单次挖矿
9
+ * npx clawminer-skill loop # 连续挖矿(自动冷却 + 重试)
10
+ * npx clawminer-skill status # 查看挖矿状态
11
+ */
12
+
13
+ const { execSync, spawn } = require('child_process');
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const readline = require('readline');
17
+
18
+ const SKILL_DIR = path.resolve(__dirname, '..');
19
+ const ENV_FILE = path.join(SKILL_DIR, '.env');
20
+ const ENV_EXAMPLE = path.join(SKILL_DIR, '.env.example');
21
+
22
+ // ========== Helpers ==========
23
+ function ask(question) {
24
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
25
+ return new Promise(resolve => {
26
+ rl.question(question, answer => {
27
+ rl.close();
28
+ resolve(answer.trim());
29
+ });
30
+ });
31
+ }
32
+
33
+ function log(emoji, msg) {
34
+ console.log(`${emoji} ${msg}`);
35
+ }
36
+
37
+ // ========== Commands ==========
38
+
39
+ /**
40
+ * init — 初始化 Skill,引导用户配置钱包
41
+ */
42
+ async function init() {
43
+ console.log('\n🦞 ClawMiner Skill 初始化\n');
44
+
45
+ // 1. Check if already initialized
46
+ if (fs.existsSync(ENV_FILE)) {
47
+ log('✅', '.env 文件已存在,Skill 已配置。');
48
+ log('💡', '如需重新配置,请删除 .env 文件后重试。');
49
+ console.log('');
50
+ return;
51
+ }
52
+
53
+ // 2. Install dependencies if needed
54
+ const nodeModules = path.join(SKILL_DIR, 'node_modules');
55
+ if (!fs.existsSync(nodeModules)) {
56
+ log('📦', '正在安装依赖...');
57
+ execSync('npm install', { cwd: SKILL_DIR, stdio: 'inherit' });
58
+ console.log('');
59
+ }
60
+
61
+ // 3. Wallet security warning
62
+ console.log(' ┌─────────────────────────────────────────────────┐');
63
+ console.log(' │ ⚠️ 安全提醒 │');
64
+ console.log(' │ │');
65
+ console.log(' │ 请使用【专用挖矿钱包】,不要使用你的主钱包! │');
66
+ console.log(' │ │');
67
+ console.log(' │ 挖矿钱包只需存放少量 BNB 作为 Gas 费。 │');
68
+ console.log(' │ 如果还没有挖矿钱包,请在 MetaMask 中新建一个。 │');
69
+ console.log(' │ │');
70
+ console.log(' │ ❌ 主钱包(存有大额资产) │');
71
+ console.log(' │ ✅ 专用挖矿钱包(仅存少量 BNB) │');
72
+ console.log(' └─────────────────────────────────────────────────┘\n');
73
+
74
+ // 4. Get private key
75
+ const privateKey = await ask(' 🔑 请输入你的【挖矿钱包】私钥(0x 开头):\n > ');
76
+
77
+ if (!privateKey || !privateKey.startsWith('0x')) {
78
+ log('❌', '私钥格式不正确,请确保以 0x 开头。');
79
+ return;
80
+ }
81
+
82
+ // 5. Ask for network
83
+ const network = await ask('\n 🌐 选择网络 [testnet/mainnet](默认 testnet):\n > ');
84
+ const selectedNetwork = (network === 'mainnet') ? 'mainnet' : 'testnet';
85
+
86
+ // 6. Set RPC and contract based on network
87
+ let rpcUrl, contractAddress;
88
+ if (selectedNetwork === 'mainnet') {
89
+ rpcUrl = 'https://bsc.publicnode.com';
90
+ contractAddress = await ask('\n 📄 请输入主网合约地址:\n > ');
91
+ } else {
92
+ rpcUrl = 'https://bsc-testnet.publicnode.com';
93
+ contractAddress = '0xCe9eAa062Ca1F6a8817f229921Ec79ac20705c38';
94
+ }
95
+
96
+ // 7. Write .env
97
+ const envContent = `# ClawMiner Skill Configuration
98
+ # ⚠️ 此文件包含私钥,请勿分享或上传!
99
+
100
+ PRIVATE_KEY=${privateKey}
101
+ RPC_URL=${rpcUrl}
102
+ CONTRACT_ADDRESS=${contractAddress}
103
+ NETWORK=${selectedNetwork}
104
+ `;
105
+
106
+ fs.writeFileSync(ENV_FILE, envContent);
107
+ log('✅', '配置完成!.env 文件已创建。\n');
108
+
109
+ // 8. Show next steps
110
+ console.log(' 📋 接下来你可以:');
111
+ console.log(' ├─ npx clawminer-skill mine 单次挖矿');
112
+ console.log(' ├─ npx clawminer-skill loop 连续挖矿(推荐)');
113
+ console.log(' └─ npx clawminer-skill status 查看状态\n');
114
+ }
115
+
116
+ /**
117
+ * Run mining script with given args
118
+ */
119
+ function runMine(args) {
120
+ const mineScript = path.join(SKILL_DIR, 'scripts', 'mine.js');
121
+
122
+ if (!fs.existsSync(ENV_FILE)) {
123
+ log('❌', '尚未配置!请先运行:npx clawminer-skill init');
124
+ process.exit(1);
125
+ }
126
+
127
+ const child = spawn('node', [mineScript, ...args], {
128
+ cwd: SKILL_DIR,
129
+ stdio: 'inherit',
130
+ env: { ...process.env }
131
+ });
132
+
133
+ child.on('close', code => process.exit(code));
134
+ }
135
+
136
+ // ========== CLI Router ==========
137
+ const command = process.argv[2];
138
+
139
+ switch (command) {
140
+ case 'init':
141
+ init().catch(err => {
142
+ console.error('❌ 初始化错误:', err.message);
143
+ process.exit(1);
144
+ });
145
+ break;
146
+ case 'mine':
147
+ runMine([]);
148
+ break;
149
+ case 'loop':
150
+ runMine(['--loop']);
151
+ break;
152
+ case 'status':
153
+ runMine(['--status']);
154
+ break;
155
+ case 'dry-run':
156
+ runMine(['--dry-run']);
157
+ break;
158
+ default:
159
+ console.log(`
160
+ 🦞 ClawMiner Skill v1.0.0
161
+
162
+ 命令:
163
+ npx clawminer-skill init 初始化配置(首次使用)
164
+ npx clawminer-skill mine 单次挖矿
165
+ npx clawminer-skill loop 连续挖矿 24/7(推荐)
166
+ npx clawminer-skill status 查看挖矿状态
167
+ npx clawminer-skill dry-run 模拟挖矿(不提交交易)
168
+
169
+ GitHub: https://github.com/ClawMiner-Project/clawminer-skill
170
+ `);
171
+ break;
172
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "clawminer-skill",
3
+ "version": "1.0.0",
4
+ "description": "ClawMiner PoW Mining Skill for OpenClaw Agent",
5
+ "main": "scripts/mine.js",
6
+ "bin": {
7
+ "clawminer-skill": "bin/cli.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "scripts/",
12
+ "SKILL.md",
13
+ "README.md",
14
+ ".env.example"
15
+ ],
16
+ "scripts": {
17
+ "mine": "node scripts/mine.js",
18
+ "status": "node scripts/mine.js --status",
19
+ "loop": "node scripts/mine.js --loop"
20
+ },
21
+ "keywords": [
22
+ "clawminer",
23
+ "pow",
24
+ "mining",
25
+ "bsc",
26
+ "web3",
27
+ "openclaw"
28
+ ],
29
+ "author": "ClawMiner-Project",
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "ethers": "^6.13.0",
33
+ "dotenv": "^16.4.0"
34
+ }
35
+ }
@@ -0,0 +1,435 @@
1
+ /**
2
+ * ClawMiner Skill - PoW Mining Script
3
+ *
4
+ * Usage:
5
+ * node scripts/mine.js # Mine once
6
+ * node scripts/mine.js --status # Show status only
7
+ * node scripts/mine.js --loop # Continuous mining loop
8
+ * node scripts/mine.js --dry-run # PoW only, no transaction
9
+ */
10
+
11
+ require('dotenv').config();
12
+ const { ethers } = require('ethers');
13
+
14
+ // ========== Configuration ==========
15
+ const CONFIG = {
16
+ // From environment or defaults
17
+ PRIVATE_KEY: process.env.PRIVATE_KEY,
18
+ RPC_URL: process.env.RPC_URL || 'https://bsc-testnet.publicnode.com',
19
+ CONTRACT_ADDRESS: process.env.CONTRACT_ADDRESS || '0xCe9eAa062Ca1F6a8817f229921Ec79ac20705c38',
20
+ NETWORK: process.env.NETWORK || 'testnet',
21
+
22
+ // Mining parameters
23
+ MAX_ATTEMPTS: 500000,
24
+ MAX_RETRY: 5,
25
+ RETRY_DELAY_MS: 2000,
26
+ GAS_LIMIT: 300000,
27
+ GAS_BUFFER_PERCENT: 20,
28
+ COOLDOWN_SECONDS: 300, // 5 minutes
29
+ };
30
+
31
+ // ========== ABI ==========
32
+ const ABI = [
33
+ "function currentDifficulty() view returns (uint256)",
34
+ "function cooldownRemaining(address) view returns (uint256)",
35
+ "function mine(bytes32,uint256,uint256)",
36
+ "function balanceOf(address) view returns (uint256)",
37
+ "function getMiningInfo(address) view returns (uint256,uint256,uint256,uint256,uint256,uint256)",
38
+ "function currentBlockReward() view returns (uint256)",
39
+ "function totalMined() view returns (uint256)",
40
+ "function miningProgress() view returns (uint256)",
41
+ "function currentPhase() view returns (uint256)",
42
+ "function remainingSupply() view returns (uint256)"
43
+ ];
44
+
45
+ // ========== Utility Functions ==========
46
+ function log(emoji, message) {
47
+ const timestamp = new Date().toLocaleTimeString();
48
+ console.log(`[${timestamp}] ${emoji} ${message}`);
49
+ }
50
+
51
+ function formatTime(seconds) {
52
+ if (seconds < 60) return `${seconds}秒`;
53
+ const mins = Math.floor(seconds / 60);
54
+ const secs = seconds % 60;
55
+ return `${mins}分${secs > 0 ? secs + '秒' : ''}`;
56
+ }
57
+
58
+ function formatNumber(n) {
59
+ return Number(n).toLocaleString();
60
+ }
61
+
62
+ // ========== ClawMiner Agent ==========
63
+ class ClawMinerAgent {
64
+ constructor() {
65
+ if (!CONFIG.PRIVATE_KEY) {
66
+ console.error('❌ 错误:未设置 PRIVATE_KEY!');
67
+ console.error(' 请复制 .env.example 为 .env 并填入你的私钥:');
68
+ console.error(' cp .env.example .env');
69
+ process.exit(1);
70
+ }
71
+
72
+ this.provider = new ethers.JsonRpcProvider(CONFIG.RPC_URL);
73
+ this.wallet = new ethers.Wallet(CONFIG.PRIVATE_KEY, this.provider);
74
+ this.address = this.wallet.address;
75
+ this.contract = new ethers.Contract(CONFIG.CONTRACT_ADDRESS, ABI, this.wallet);
76
+ }
77
+
78
+ /**
79
+ * Get full mining status
80
+ */
81
+ async getStatus() {
82
+ try {
83
+ const [info, progress, cooldown, balance] = await Promise.all([
84
+ this.contract.getMiningInfo(this.address),
85
+ this.contract.miningProgress(),
86
+ this.contract.cooldownRemaining(this.address),
87
+ this.contract.balanceOf(this.address)
88
+ ]);
89
+
90
+ return {
91
+ totalMined: ethers.formatEther(info[0]),
92
+ remaining: ethers.formatEther(info[1]),
93
+ difficulty: Number(info[2]),
94
+ reward: ethers.formatEther(info[3]),
95
+ cooldownEnd: Number(info[4]),
96
+ nextHalving: ethers.formatEther(info[5]),
97
+ progress: (Number(progress) / 100).toFixed(2) + '%',
98
+ cooldownRemaining: Number(cooldown),
99
+ balance: ethers.formatEther(balance)
100
+ };
101
+ } catch (error) {
102
+ throw new Error(`Failed to get status: ${error.message}`);
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Display mining status
108
+ */
109
+ async showStatus() {
110
+ log('📊', '正在获取挖矿状态...\n');
111
+
112
+ const status = await this.getStatus();
113
+ const explorerBase = CONFIG.NETWORK === 'mainnet'
114
+ ? 'https://bscscan.com'
115
+ : 'https://testnet.bscscan.com';
116
+
117
+ console.log(' ┌─────────────────────────────────────────┐');
118
+ console.log(' │ 🦞 ClawMiner 挖矿状态 │');
119
+ console.log(' ├─────────────────────────────────────────┤');
120
+ console.log(` │ 钱包: ${this.address.substring(0, 6)}...${this.address.substring(38)}`);
121
+ console.log(` │ 网络: BSC ${CONFIG.NETWORK}`);
122
+ console.log(` │ 余额: ${formatNumber(status.balance)} CLAWMINER`);
123
+ console.log(' ├─────────────────────────────────────────┤');
124
+ console.log(` │ 难度: ${status.difficulty} 字节`);
125
+ console.log(` │ 奖励: ${status.reward} CLAWMINER / 次`);
126
+ console.log(` │ 进度: ${status.progress}`);
127
+ console.log(` │ 剩余可挖: ${formatNumber(status.remaining)} CLAWMINER`);
128
+ console.log(' ├─────────────────────────────────────────┤');
129
+
130
+ if (status.cooldownRemaining > 0) {
131
+ console.log(` │ 冷却: ⏱️ 还需 ${formatTime(status.cooldownRemaining)}`);
132
+ } else {
133
+ console.log(` │ 冷却: ✅ 可以挖矿!`);
134
+ }
135
+
136
+ console.log(' └─────────────────────────────────────────┘');
137
+ console.log(`\n 🔍 ${explorerBase}/address/${this.address}\n`);
138
+
139
+ return status;
140
+ }
141
+
142
+ /**
143
+ * Check if mining is possible
144
+ */
145
+ async canMine() {
146
+ const cooldown = await this.contract.cooldownRemaining(this.address);
147
+ return {
148
+ canMine: cooldown === 0n,
149
+ remaining: Number(cooldown)
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Find a valid PoW proof
155
+ */
156
+ async findProof(blockNumber, timestamp, difficulty) {
157
+ const targetHexChars = difficulty * 2;
158
+ const startTime = Date.now();
159
+
160
+ let nonce = 0;
161
+
162
+ for (let i = 0; i < CONFIG.MAX_ATTEMPTS; i++) {
163
+ const hash = ethers.solidityPackedKeccak256(
164
+ ['uint256', 'uint256', 'address', 'uint256'],
165
+ [blockNumber, timestamp, this.address, nonce]
166
+ );
167
+
168
+ const prefix = hash.substring(2, 2 + targetHexChars);
169
+ const allZeros = prefix.split('').every(c => c === '0');
170
+
171
+ if (allZeros) {
172
+ return {
173
+ success: true,
174
+ proof: hash,
175
+ nonce: nonce,
176
+ attempts: i + 1,
177
+ elapsed: Date.now() - startTime
178
+ };
179
+ }
180
+
181
+ nonce++;
182
+
183
+ // Progress report every 100k attempts
184
+ if (i % 100000 === 0 && i > 0) {
185
+ log('⛏️', `正在计算 PoW... 已尝试 ${formatNumber(i)} 次(${Math.floor((Date.now() - startTime) / 1000)}秒)`);
186
+ }
187
+ }
188
+
189
+ return {
190
+ success: false,
191
+ attempts: CONFIG.MAX_ATTEMPTS,
192
+ elapsed: Date.now() - startTime
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Execute single mine
198
+ */
199
+ async mine(dryRun = false) {
200
+ log('🦞', 'ClawMiner — 开始挖矿\n');
201
+
202
+ // 1. Check cooldown
203
+ log('⏱️', '检查冷却状态...');
204
+ const canMineResult = await this.canMine();
205
+
206
+ if (!canMineResult.canMine) {
207
+ log('⏱️', `冷却中 — 还需 ${formatTime(canMineResult.remaining)}`);
208
+ return {
209
+ status: 'cooling',
210
+ remaining: canMineResult.remaining,
211
+ message: `冷却中,还需 ${formatTime(canMineResult.remaining)}`
212
+ };
213
+ }
214
+
215
+ // 2. Get current state
216
+ const status = await this.getStatus();
217
+ log('📊', `难度:${status.difficulty} | 奖励:${status.reward} CLAWMINER | 进度:${status.progress}`);
218
+
219
+ // 3. Get block info
220
+ const [blockNumber, block] = await Promise.all([
221
+ this.provider.getBlockNumber(),
222
+ this.provider.getBlock()
223
+ ]);
224
+ const timestamp = block.timestamp;
225
+ log('🔗', `区块:${blockNumber} | 时间戳:${timestamp}`);
226
+
227
+ // 4. Find proof
228
+ log('⛏️', '正在计算 PoW 证明...');
229
+ const proofResult = await this.findProof(blockNumber, Number(timestamp), status.difficulty);
230
+
231
+ if (!proofResult.success) {
232
+ log('❌', `尝试 ${formatNumber(proofResult.attempts)} 次后未找到有效解(${Math.floor(proofResult.elapsed / 1000)}秒)`);
233
+ return {
234
+ status: 'failed',
235
+ message: `尝试 ${formatNumber(proofResult.attempts)} 次未找到有效 Proof`,
236
+ attempts: proofResult.attempts,
237
+ elapsed: proofResult.elapsed
238
+ };
239
+ }
240
+
241
+ log('✅', `找到有效 Proof!尝试:${formatNumber(proofResult.attempts)} 次 | 耗时:${Math.floor(proofResult.elapsed / 1000)}秒`);
242
+ log('🔑', `Hash: ${proofResult.proof.substring(0, 22)}...`);
243
+
244
+ // Dry run stops here
245
+ if (dryRun) {
246
+ log('🧪', '模拟运行 — 跳过交易提交');
247
+ return {
248
+ status: 'dry-run',
249
+ proof: proofResult.proof,
250
+ nonce: proofResult.nonce,
251
+ attempts: proofResult.attempts,
252
+ elapsed: proofResult.elapsed,
253
+ message: '模拟运行完成 — Proof 有效'
254
+ };
255
+ }
256
+
257
+ // 5. Estimate gas
258
+ log('📤', '准备提交交易...');
259
+ let gasLimit = CONFIG.GAS_LIMIT;
260
+
261
+ try {
262
+ const estimate = await this.contract.mine.estimateGas(
263
+ proofResult.proof, blockNumber, timestamp
264
+ );
265
+ gasLimit = Math.floor(Number(estimate) * (1 + CONFIG.GAS_BUFFER_PERCENT / 100));
266
+ log('⛽', `Gas 估算:${estimate} → ${gasLimit}(含缓冲)`);
267
+ } catch (e) {
268
+ log('⛽', `Gas 估算失败,使用默认值:${gasLimit}`);
269
+ }
270
+
271
+ // 6. Submit transaction
272
+ try {
273
+ const tx = await this.contract.mine(
274
+ proofResult.proof, blockNumber, timestamp,
275
+ { gasLimit }
276
+ );
277
+
278
+ log('📤', `交易哈希:${tx.hash}`);
279
+ log('⏳', '等待链上确认...');
280
+
281
+ const receipt = await tx.wait();
282
+ const explorerBase = CONFIG.NETWORK === 'mainnet'
283
+ ? 'https://bscscan.com'
284
+ : 'https://testnet.bscscan.com';
285
+
286
+ if (receipt.status === 1) {
287
+ const balance = await this.contract.balanceOf(this.address);
288
+
289
+ log('🎉', `挖矿成功!获得 ${status.reward} CLAWMINER`);
290
+ log('💰', `总余额:${ethers.formatEther(balance)} CLAWMINER`);
291
+ log('🔍', `${explorerBase}/tx/${tx.hash}`);
292
+
293
+ return {
294
+ status: 'success',
295
+ txHash: tx.hash,
296
+ gasUsed: Number(receipt.gasUsed),
297
+ reward: status.reward,
298
+ balance: ethers.formatEther(balance),
299
+ proof: proofResult.proof,
300
+ attempts: proofResult.attempts,
301
+ message: `挖矿成功!获得 ${status.reward} CLAWMINER`
302
+ };
303
+ } else {
304
+ log('❌', `交易失败 (status=0)`);
305
+ return { status: 'failed', txHash: tx.hash, message: '交易被回滚' };
306
+ }
307
+ } catch (error) {
308
+ if (error.message.includes('Cooldown')) {
309
+ log('⏱️', '冷却中 — 请稍后重试');
310
+ return { status: 'cooling', message: '冷却中,请稍后重试' };
311
+ }
312
+ if (error.message.includes('Proof already used')) {
313
+ log('⚠️', 'Proof 已被使用 — 将使用新的 Proof 重试');
314
+ return { status: 'retry', message: 'Proof 已被使用' };
315
+ }
316
+ throw error;
317
+ }
318
+ }
319
+
320
+ /**
321
+ * Mine with retry
322
+ */
323
+ async mineWithRetry(dryRun = false) {
324
+ let retryCount = 0;
325
+
326
+ while (retryCount <= CONFIG.MAX_RETRY) {
327
+ try {
328
+ const result = await this.mine(dryRun);
329
+
330
+ if (result.status === 'success' || result.status === 'cooling' || result.status === 'dry-run') {
331
+ return result;
332
+ }
333
+
334
+ retryCount++;
335
+ if (retryCount > CONFIG.MAX_RETRY) {
336
+ log('❌', `已达最大重试次数 (${CONFIG.MAX_RETRY})`);
337
+ return { status: 'exhausted', message: `重试 ${CONFIG.MAX_RETRY} 次后仍失败` };
338
+ }
339
+
340
+ log('🔄', `${CONFIG.RETRY_DELAY_MS / 1000}秒后重试 (${retryCount}/${CONFIG.MAX_RETRY})...`);
341
+ await new Promise(r => setTimeout(r, CONFIG.RETRY_DELAY_MS));
342
+
343
+ } catch (error) {
344
+ retryCount++;
345
+ if (retryCount > CONFIG.MAX_RETRY) {
346
+ log('❌', `Error: ${error.message}`);
347
+ return { status: 'error', message: error.message };
348
+ }
349
+ log('⚠️', `错误:${error.message}`);
350
+ log('🔄', `${CONFIG.RETRY_DELAY_MS / 1000}秒后重试 (${retryCount}/${CONFIG.MAX_RETRY})...`);
351
+ await new Promise(r => setTimeout(r, CONFIG.RETRY_DELAY_MS));
352
+ }
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Continuous mining loop
358
+ */
359
+ async loop() {
360
+ log('🔁', '启动连续挖矿循环(按 Ctrl+C 停止)\n');
361
+ let mineCount = 0;
362
+
363
+ while (true) {
364
+ mineCount++;
365
+ log('🔁', `\n${'='.repeat(50)}`);
366
+ log('🔁', `第 ${mineCount} 轮挖矿`);
367
+ log('🔁', `${'='.repeat(50)}\n`);
368
+
369
+ const result = await this.mineWithRetry();
370
+
371
+ if (result.status === 'cooling') {
372
+ const waitTime = result.remaining || CONFIG.COOLDOWN_SECONDS;
373
+ log('⏱️', `等待冷却 ${formatTime(waitTime)}...\n`);
374
+
375
+ // Countdown display
376
+ let remaining = waitTime;
377
+ while (remaining > 0) {
378
+ process.stdout.write(`\r ⏱️ 冷却中:还需 ${formatTime(remaining)}... `);
379
+ await new Promise(r => setTimeout(r, 10000)); // Update every 10s
380
+ remaining -= 10;
381
+ }
382
+ console.log('\n');
383
+ } else if (result.status === 'success') {
384
+ // Wait for cooldown after successful mine
385
+ log('⏱️', `等待冷却 ${formatTime(CONFIG.COOLDOWN_SECONDS)}...\n`);
386
+ let remaining = CONFIG.COOLDOWN_SECONDS;
387
+ while (remaining > 0) {
388
+ process.stdout.write(`\r ⏱️ 冷却中:还需 ${formatTime(remaining)}... `);
389
+ await new Promise(r => setTimeout(r, 10000));
390
+ remaining -= 10;
391
+ }
392
+ console.log('\n');
393
+ } else {
394
+ // On error, wait a bit before retrying
395
+ log('⚠️', '30秒后重新尝试...');
396
+ await new Promise(r => setTimeout(r, 30000));
397
+ }
398
+ }
399
+ }
400
+ }
401
+
402
+ // ========== CLI Entry Point ==========
403
+ async function main() {
404
+ const args = process.argv.slice(2);
405
+ const agent = new ClawMinerAgent();
406
+
407
+ console.log('\n 🦞 ClawMiner Skill v1.0.0');
408
+ console.log(` 📍 网络:BSC ${CONFIG.NETWORK}`);
409
+ console.log(` 👛 钱包:${agent.address}\n`);
410
+
411
+ if (args.includes('--status')) {
412
+ await agent.showStatus();
413
+ } else if (args.includes('--loop')) {
414
+ await agent.loop();
415
+ } else if (args.includes('--dry-run')) {
416
+ await agent.mineWithRetry(true);
417
+ } else {
418
+ const result = await agent.mineWithRetry();
419
+ console.log('\n' + '─'.repeat(50));
420
+ console.log(` 结果:${result.status}`);
421
+ console.log(` ${result.message}`);
422
+ if (result.txHash) {
423
+ const explorerBase = CONFIG.NETWORK === 'mainnet'
424
+ ? 'https://bscscan.com'
425
+ : 'https://testnet.bscscan.com';
426
+ console.log(` 🔍 ${explorerBase}/tx/${result.txHash}`);
427
+ }
428
+ console.log('─'.repeat(50) + '\n');
429
+ }
430
+ }
431
+
432
+ main().catch(error => {
433
+ console.error('\n❌ 致命错误:', error.message);
434
+ process.exit(1);
435
+ });