diff --git a/explorer/dashboard/README.md b/explorer/dashboard/README.md
index 30866be6..63647149 100644
--- a/explorer/dashboard/README.md
+++ b/explorer/dashboard/README.md
@@ -1,20 +1,33 @@
-# RustChain Block Explorer Dashboard
+# RustChain Explorer - Miner Dashboard
-Self-hostable dashboard for RustChain network stats.
+Real-time miner dashboard for the RustChain Proof-of-Antiquity blockchain.
## Features
-- Health status from `/health`
-- Active miners from `/api/miners`
-- Current epoch snapshot from `/epoch`
-- Transaction list from `/api/transactions` (if available)
-
-## Run
-```bash
-cd explorer/dashboard
-python3 -m venv .venv && source .venv/bin/activate
-pip install -r requirements.txt
-export RUSTCHAIN_API_BASE="https://rustchain.org"
-python app.py
-```
-
-Open: `http://localhost:8787`
+
+- **Real-time miner status** - Live online/offline indicators
+- **Architecture badges** - Display hardware type (G4, G5, POWER8, Apple Silicon, etc.)
+- **Antiquity multipliers** - Visual display of mining multipliers
+- **Auto-refresh** - Updates every 30 seconds
+- **Responsive design** - Works on desktop and mobile
+- **Dark theme** - RustChain branded colors
+
+## Usage
+
+Simply open `index.html` in a browser. The dashboard fetches data from:
+- `https://explorer.rustchain.org/api/miners`
+
+## Deployment
+
+Drop `index.html` into any web server, or serve via nginx on port 5555.
+
+## Bounty
+
+This addresses Issue #686 - Tier 1: Miner Dashboard (50 RTC)
+
+## Demo
+
+Open `index.html` directly in a browser to see the live dashboard.
+
+## License
+
+MIT
diff --git a/explorer/dashboard/agent-economy.html b/explorer/dashboard/agent-economy.html
new file mode 100644
index 00000000..cc6866ea
--- /dev/null
+++ b/explorer/dashboard/agent-economy.html
@@ -0,0 +1,410 @@
+
+
+
+
+
+ RustChain Agent Economy Marketplace
+
+
+
+
+
+ π€ RustChain Agent Economy
+ Job Marketplace
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/explorer/dashboard/full-explorer.html b/explorer/dashboard/full-explorer.html
new file mode 100644
index 00000000..1fea6880
--- /dev/null
+++ b/explorer/dashboard/full-explorer.html
@@ -0,0 +1,433 @@
+
+
+
+
+
+ RustChain Explorer - Full Suite
+
+
+
+
+
+ βοΈ RustChain Explorer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Node Status
+
+
+
Node 1 (Primary)
+
Checking...
+
+
+
+
+
Epoch Info
+
+
+
+
+
+
+
diff --git a/explorer/dashboard/index.html b/explorer/dashboard/index.html
new file mode 100644
index 00000000..75250d15
--- /dev/null
+++ b/explorer/dashboard/index.html
@@ -0,0 +1,368 @@
+
+
+
+
+
+ RustChain Explorer - Miner Dashboard
+
+
+
+
+
+
+
+
+
+ π¨βπ Active Miners
+
+
+
+
+
+
+ Last updated: - | Auto-refresh: 30s
+
+
+
+
+
+
diff --git a/sdk/cli/.gitignore b/sdk/cli/.gitignore
new file mode 100644
index 00000000..dd6e803c
--- /dev/null
+++ b/sdk/cli/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+dist/
+*.log
+.DS_Store
diff --git a/sdk/cli/README.md b/sdk/cli/README.md
new file mode 100644
index 00000000..49c4133b
--- /dev/null
+++ b/sdk/cli/README.md
@@ -0,0 +1,78 @@
+# RustChain Agent Economy CLI Tool
+
+Command-line tool for interacting with the RustChain Agent Economy marketplace.
+
+## Installation
+
+```bash
+npm install -g rustchain-agent-cli
+```
+
+## Usage
+
+### View Marketplace Stats
+```bash
+rustchain-agent stats
+```
+
+### Browse Jobs
+```bash
+# List all jobs
+rustchain-agent jobs
+
+# Filter by category
+rustchain-agent jobs --category code
+
+# Limit results
+rustchain-agent jobs --limit 20
+```
+
+### View Job Details
+```bash
+rustchain-agent job
+```
+
+### Post a Job
+```bash
+rustchain-agent post
+```
+
+### Claim a Job
+```bash
+rustchain-agent claim
+```
+
+### Submit Delivery
+```bash
+rustchain-agent deliver
+```
+
+### Check Reputation
+```bash
+rustchain-agent reputation
+```
+
+## Development
+
+```bash
+npm install
+npm run build
+node dist/index.js stats
+```
+
+## Categories
+
+- research
+- code
+- video
+- audio
+- writing
+- translation
+- data
+- design
+- testing
+- other
+
+## License
+
+MIT
diff --git a/sdk/cli/package.json b/sdk/cli/package.json
new file mode 100644
index 00000000..59def3ca
--- /dev/null
+++ b/sdk/cli/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "rustchain-agent-cli",
+ "version": "1.0.0",
+ "description": "RustChain Agent Economy CLI Tool",
+ "main": "dist/index.js",
+ "bin": {
+ "rustchain-agent": "./dist/index.js"
+ },
+ "scripts": {
+ "build": "tsc",
+ "test": "echo \"No tests yet\" && exit 0"
+ },
+ "keywords": ["rustchain", "blockchain", "agent", "cli"],
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.6.0",
+ "commander": "^11.0.0",
+ "chalk": "^4.1.0",
+ "inquirer": "^8.0.0"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "@types/inquirer": "^8.0.0",
+ "typescript": "^5.0.0"
+ }
+}
diff --git a/sdk/cli/src/index.ts b/sdk/cli/src/index.ts
new file mode 100644
index 00000000..d109d1b8
--- /dev/null
+++ b/sdk/cli/src/index.ts
@@ -0,0 +1,244 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+import axios from 'axios';
+
+const API_BASE = 'https://rustchain.org';
+
+const client = axios.create({
+ baseURL: API_BASE,
+ headers: { 'Content-Type': 'application/json' }
+});
+
+// Helper functions
+async function getMarketStats() {
+ try {
+ const response = await client.get('/agent/stats');
+ return response.data;
+ } catch (error: any) {
+ console.error(chalk.red('Error fetching stats:'), error.message);
+ return null;
+ }
+}
+
+async function getJobs(category?: string, limit: number = 10) {
+ try {
+ const params: any = { limit };
+ if (category) params.category = category;
+ const response = await client.get('/agent/jobs', { params });
+ return response.data;
+ } catch (error: any) {
+ console.error(chalk.red('Error fetching jobs:'), error.message);
+ return [];
+ }
+}
+
+async function getJobDetails(jobId: string) {
+ try {
+ const response = await client.get(`/agent/jobs/${jobId}`);
+ return response.data;
+ } catch (error: any) {
+ console.error(chalk.red('Error fetching job:'), error.message);
+ return null;
+ }
+}
+
+async function postJob(wallet: string, title: string, description: string, category: string, reward: number, tags: string[]) {
+ try {
+ const response = await client.post('/agent/jobs', {
+ poster_wallet: wallet,
+ title,
+ description,
+ category,
+ reward_rtc: reward,
+ tags
+ });
+ return response.data;
+ } catch (error: any) {
+ console.error(chalk.red('Error posting job:'), error.message);
+ return null;
+ }
+}
+
+async function claimJob(jobId: string, workerWallet: string) {
+ try {
+ const response = await client.post(`/agent/jobs/${jobId}/claim`, {
+ worker_wallet: workerWallet
+ });
+ return response.data;
+ } catch (error: any) {
+ console.error(chalk.red('Error claiming job:'), error.message);
+ return null;
+ }
+}
+
+async function deliverJob(jobId: string, workerWallet: string, url: string, summary: string) {
+ try {
+ const response = await client.post(`/agent/jobs/${jobId}/deliver`, {
+ worker_wallet: workerWallet,
+ deliverable_url: url,
+ result_summary: summary
+ });
+ return response.data;
+ } catch (error: any) {
+ console.error(chalk.red('Error delivering job:'), error.message);
+ return null;
+ }
+}
+
+async function getReputation(wallet: string) {
+ try {
+ const response = await client.get(`/agent/reputation/${wallet}`);
+ return response.data;
+ } catch (error: any) {
+ console.error(chalk.red('Error fetching reputation:'), error.message);
+ return null;
+ }
+}
+
+// CLI Commands
+const program = new Command();
+
+program
+ .name('rustchain-agent')
+ .description('RustChain Agent Economy CLI Tool')
+ .version('1.0.0');
+
+program
+ .command('stats')
+ .description('Show marketplace statistics')
+ .action(async () => {
+ console.log(chalk.blue('\nπ Marketplace Statistics\n'));
+ const stats = await getMarketStats();
+ if (stats) {
+ console.log(chalk.green(`Total Jobs: ${stats.total_jobs}`));
+ console.log(chalk.green(`Open Jobs: ${stats.open_jobs}`));
+ console.log(chalk.green(`Completed: ${stats.completed_jobs}`));
+ console.log(chalk.green(`RTC Locked: ${stats.total_rtc_locked}`));
+ console.log(chalk.green(`Average Reward: ${stats.average_reward} RTC`));
+ if (stats.top_categories?.length) {
+ console.log(chalk.yellow('\nTop Categories:'));
+ stats.top_categories.forEach((c: any) => {
+ console.log(` - ${c.category}: ${c.count}`);
+ });
+ }
+ }
+ console.log('');
+ });
+
+program
+ .command('jobs')
+ .description('Browse open jobs')
+ .option('-c, --category ', 'Filter by category')
+ .option('-l, --limit ', 'Number of jobs', '10')
+ .action(async (options) => {
+ console.log(chalk.blue('\nπΌ Open Jobs\n'));
+ const jobs = await getJobs(options.category, parseInt(options.limit));
+ if (jobs?.length) {
+ jobs.forEach((job: any, i: number) => {
+ console.log(chalk.cyan(`[${i + 1}] ${job.title}`));
+ console.log(` Reward: ${chalk.green(job.reward_rtc + ' RTC')} | Category: ${job.category}`);
+ console.log(` ID: ${job.id}\n`);
+ });
+ } else {
+ console.log(chalk.yellow('No jobs found.\n'));
+ }
+ });
+
+program
+ .command('job ')
+ .description('Get job details')
+ .action(async (jobId) => {
+ console.log(chalk.blue(`\nπ Job Details: ${jobId}\n`));
+ const job = await getJobDetails(jobId);
+ if (job) {
+ console.log(chalk.cyan('Title:'), job.title);
+ console.log(chalk.cyan('Description:'), job.description);
+ console.log(chalk.cyan('Reward:'), chalk.green(job.reward_rtc + ' RTC'));
+ console.log(chalk.cyan('Category:'), job.category);
+ console.log(chalk.cyan('Status:'), job.status);
+ console.log(chalk.cyan('Poster:'), job.poster_wallet);
+ if (job.tags?.length) {
+ console.log(chalk.cyan('Tags:'), job.tags.join(', '));
+ }
+ }
+ console.log('');
+ });
+
+program
+ .command('post')
+ .description('Post a new job')
+ .action(async () => {
+ console.log(chalk.blue('\nπ Post New Job\n'));
+ const answers = await inquirer.prompt([
+ { name: 'wallet', message: 'Your wallet name:', type: 'input' },
+ { name: 'title', message: 'Job title:', type: 'input' },
+ { name: 'description', message: 'Description:', type: 'input' },
+ { name: 'category', message: 'Category (research/code/video/audio/writing/translation/data/design/other):', type: 'input' },
+ { name: 'reward', message: 'Reward (RTC):', type: 'number' },
+ { name: 'tags', message: 'Tags (comma-separated):', type: 'input' }
+ ]);
+
+ const tags = answers.tags ? answers.tags.split(',').map((t: string) => t.trim()) : [];
+ const result = await postJob(answers.wallet, answers.title, answers.description, answers.category, answers.reward, tags);
+
+ if (result) {
+ console.log(chalk.green('\nβ
Job posted successfully!'));
+ console.log(chalk.cyan('Job ID:'), result.id || result.job_id);
+ }
+ console.log('');
+ });
+
+program
+ .command('claim ')
+ .description('Claim a job')
+ .action(async (jobId) => {
+ const answers = await inquirer.prompt([
+ { name: 'wallet', message: 'Your wallet name:', type: 'input' }
+ ]);
+
+ console.log(chalk.blue(`\nβ Claiming job ${jobId}...\n`));
+ const result = await claimJob(jobId, answers.wallet);
+
+ if (result) {
+ console.log(chalk.green('β
Job claimed successfully!'));
+ }
+ console.log('');
+ });
+
+program
+ .command('deliver ')
+ .description('Submit delivery for a job')
+ .action(async (jobId) => {
+ const answers = await inquirer.prompt([
+ { name: 'wallet', message: 'Your wallet name:', type: 'input' },
+ { name: 'url', message: 'Deliverable URL:', type: 'input' },
+ { name: 'summary', message: 'Summary of work:', type: 'input' }
+ ]);
+
+ console.log(chalk.blue(`\nπ€ Submitting delivery for job ${jobId}...\n`));
+ const result = await deliverJob(jobId, answers.wallet, answers.url, answers.summary);
+
+ if (result) {
+ console.log(chalk.green('β
Delivery submitted successfully!'));
+ }
+ console.log('');
+ });
+
+program
+ .command('reputation ')
+ .description('Get wallet reputation')
+ .action(async (wallet) => {
+ console.log(chalk.blue(`\nβ Reputation for ${wallet}\n`));
+ const rep = await getReputation(wallet);
+ if (rep) {
+ console.log(chalk.cyan('Wallet:'), rep.wallet);
+ console.log(chalk.cyan('Trust Score:'), chalk.green(rep.trust_score));
+ console.log(chalk.cyan('Total Jobs:'), rep.total_jobs);
+ console.log(chalk.cyan('Completed:'), rep.completed_jobs);
+ console.log(chalk.cyan('Disputed:'), rep.disputed_jobs);
+ }
+ console.log('');
+ });
+
+program.parse();
diff --git a/sdk/cli/tsconfig.json b/sdk/cli/tsconfig.json
new file mode 100644
index 00000000..8099ce8c
--- /dev/null
+++ b/sdk/cli/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "commonjs",
+ "lib": ["ES2020"],
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/sdk/javascript/.gitignore b/sdk/javascript/.gitignore
new file mode 100644
index 00000000..dd6e803c
--- /dev/null
+++ b/sdk/javascript/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+dist/
+*.log
+.DS_Store
diff --git a/sdk/javascript/README.md b/sdk/javascript/README.md
new file mode 100644
index 00000000..f303b61d
--- /dev/null
+++ b/sdk/javascript/README.md
@@ -0,0 +1,97 @@
+# RustChain Agent Economy SDK
+
+JavaScript/TypeScript SDK for the RustChain Agent Economy marketplace.
+
+## Installation
+
+```bash
+npm install rustchain-agent-sdk
+```
+
+## Usage
+
+```typescript
+import { RustChainAgentSDK } from 'rustchain-agent-sdk';
+
+const sdk = new RustChainAgentSDK('https://rustchain.org');
+
+// Get marketplace stats
+const stats = await sdk.getMarketStats();
+console.log(stats);
+
+// Browse jobs
+const jobs = await sdk.getJobs('code', 10);
+console.log(jobs);
+
+// Post a new job
+const newJob = await sdk.postJob({
+ poster_wallet: 'my-wallet',
+ title: 'Write a blog post',
+ description: '500+ word article about RustChain',
+ category: 'writing',
+ reward_rtc: 5,
+ tags: ['blog', 'documentation']
+});
+console.log(newJob);
+
+// Claim a job
+await sdk.claimJob('JOB_ID', { worker_wallet: 'worker-wallet' });
+
+// Submit delivery
+await sdk.deliverJob('JOB_ID', {
+ worker_wallet: 'worker-wallet',
+ deliverable_url: 'https://my-blog.com/article',
+ result_summary: 'Published 800-word article'
+});
+
+// Accept delivery (poster)
+await sdk.acceptDelivery('JOB_ID', 'poster-wallet');
+
+// Get reputation
+const rep = await sdk.getReputation('wallet-name');
+console.log(rep);
+```
+
+## API Reference
+
+### Jobs
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `postJob(job)` | POST /agent/jobs | Post a new job |
+| `getJobs(category?, limit?)` | GET /agent/jobs | Browse jobs |
+| `getJob(jobId)` | GET /agent/jobs/:id | Get job details |
+| `claimJob(jobId, claim)` | POST /agent/jobs/:id/claim | Claim a job |
+| `deliverJob(jobId, delivery)` | POST /agent/jobs/:id/deliver | Submit delivery |
+| `acceptDelivery(jobId, wallet)` | POST /agent/jobs/:id/accept | Accept delivery |
+| `disputeJob(jobId, wallet, reason)` | POST /agent/jobs/:id/dispute | Dispute delivery |
+| `cancelJob(jobId, wallet)` | POST /agent/jobs/:id/cancel | Cancel job |
+
+### Reputation
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `getReputation(wallet)` | GET /agent/reputation/:wallet | Get wallet reputation |
+
+### Stats
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `getMarketStats()` | GET /agent/stats | Marketplace statistics |
+
+## Categories
+
+- research
+- code
+- video
+- audio
+- writing
+- translation
+- data
+- design
+- testing
+- other
+
+## License
+
+MIT
diff --git a/sdk/javascript/examples/basic.ts b/sdk/javascript/examples/basic.ts
new file mode 100644
index 00000000..fc8c11b9
--- /dev/null
+++ b/sdk/javascript/examples/basic.ts
@@ -0,0 +1,56 @@
+/**
+ * RustChain Agent Economy SDK - Example Usage
+ *
+ * This example demonstrates how to use the SDK to interact with
+ * the RustChain Agent Economy marketplace.
+ *
+ * Run with: npx ts-node examples/basic.ts
+ */
+
+import { RustChainAgentSDK, Job, MarketStats } from './src/index';
+
+async function main() {
+ // Initialize the SDK
+ const sdk = new RustChainAgentSDK('https://rustchain.org');
+
+ console.log('=== RustChain Agent Economy SDK Demo ===\n');
+
+ // Example 1: Get Marketplace Stats
+ console.log('1. Getting marketplace statistics...');
+ const stats = await sdk.getMarketStats();
+ if (stats.success && stats.data) {
+ console.log(` Total Jobs: ${stats.data.total_jobs}`);
+ console.log(` Open Jobs: ${stats.data.open_jobs}`);
+ console.log(` Completed: ${stats.data.completed_jobs}`);
+ console.log(` RTC Locked: ${stats.data.total_rtc_locked}`);
+ } else {
+ console.log(` Error: ${stats.error}`);
+ }
+ console.log('');
+
+ // Example 2: Browse Open Jobs
+ console.log('2. Browsing open jobs...');
+ const jobs = await sdk.getJobs(undefined, 5);
+ if (jobs.success && jobs.data) {
+ jobs.data.forEach((job: any, index: number) => {
+ console.log(` [${index + 1}] ${job.title}`);
+ console.log(` Reward: ${job.reward_rtc} RTC | Category: ${job.category}`);
+ });
+ } else {
+ console.log(` Error: ${jobs.error}`);
+ }
+ console.log('');
+
+ // Example 3: Get Job Details (if we have a job ID)
+ // const jobDetails = await sdk.getJob('JOB_ID');
+ // console.log('Job Details:', jobDetails);
+
+ // Example 4: Get Wallet Reputation
+ // const reputation = await sdk.getReputation('your-wallet-name');
+ // console.log('Reputation:', reputation);
+
+ console.log('=== Demo Complete ===');
+}
+
+// Run the example
+main().catch(console.error);
diff --git a/sdk/javascript/package.json b/sdk/javascript/package.json
new file mode 100644
index 00000000..bb74cbe7
--- /dev/null
+++ b/sdk/javascript/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "rustchain-agent-sdk",
+ "version": "1.0.0",
+ "description": "RustChain Agent Economy JavaScript/TypeScript SDK",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "build": "tsc",
+ "test": "echo \"No tests yet\" && exit 0"
+ },
+ "keywords": ["rustchain", "blockchain", "agent", "economy", "sdk"],
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.6.0"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "typescript": "^5.0.0"
+ }
+}
diff --git a/sdk/javascript/src/index.ts b/sdk/javascript/src/index.ts
new file mode 100644
index 00000000..40f0ba4b
--- /dev/null
+++ b/sdk/javascript/src/index.ts
@@ -0,0 +1,263 @@
+import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
+
+// Types
+export interface Job {
+ id?: string;
+ poster_wallet: string;
+ title: string;
+ description: string;
+ category: string;
+ reward_rtc: number;
+ tags?: string[];
+ status?: string;
+ created_at?: string;
+ updated_at?: string;
+}
+
+export interface JobClaim {
+ worker_wallet: string;
+}
+
+export interface JobDelivery {
+ worker_wallet: string;
+ deliverable_url: string;
+ result_summary: string;
+}
+
+export interface Reputation {
+ wallet: string;
+ trust_score: number;
+ total_jobs: number;
+ completed_jobs: number;
+ disputed_jobs: number;
+ history: JobHistoryItem[];
+}
+
+export interface JobHistoryItem {
+ job_id: string;
+ role: 'poster' | 'worker';
+ outcome: 'completed' | 'disputed' | 'cancelled';
+ timestamp: string;
+}
+
+export interface MarketStats {
+ total_jobs: number;
+ open_jobs: number;
+ completed_jobs: number;
+ total_rtc_locked: number;
+ average_reward: number;
+ top_categories: { category: string; count: number }[];
+}
+
+export interface ApiResponse {
+ success: boolean;
+ data?: T;
+ error?: string;
+}
+
+export class RustChainAgentSDK {
+ private client: AxiosInstance;
+ private baseUrl: string;
+
+ constructor(baseUrl: string = 'https://rustchain.org', apiKey?: string) {
+ this.baseUrl = baseUrl;
+
+ const config: AxiosRequestConfig = {
+ baseURL: baseUrl,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ };
+
+ if (apiKey) {
+ config.headers!['Authorization'] = `Bearer ${apiKey}`;
+ }
+
+ this.client = axios.create(config);
+ }
+
+ // ==================== Jobs ====================
+
+ /**
+ * Post a new job to the marketplace
+ * @param job - Job details
+ */
+ async postJob(job: Job): Promise> {
+ try {
+ const response = await this.client.post('/agent/jobs', job);
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ /**
+ * Browse open jobs
+ * @param category - Optional filter by category
+ * @param limit - Max number of results
+ */
+ async getJobs(category?: string, limit: number = 20): Promise> {
+ try {
+ const params: any = { limit };
+ if (category) params.category = category;
+
+ const response = await this.client.get('/agent/jobs', { params });
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ /**
+ * Get job details by ID
+ * @param jobId - Job ID
+ */
+ async getJob(jobId: string): Promise> {
+ try {
+ const response = await this.client.get(`/agent/jobs/${jobId}`);
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ /**
+ * Claim an open job
+ * @param jobId - Job ID
+ * @param claim - Claim details with worker wallet
+ */
+ async claimJob(jobId: string, claim: JobClaim): Promise> {
+ try {
+ const response = await this.client.post(`/agent/jobs/${jobId}/claim`, claim);
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ /**
+ * Submit deliverables for a job
+ * @param jobId - Job ID
+ * @param delivery - Delivery details
+ */
+ async deliverJob(jobId: string, delivery: JobDelivery): Promise> {
+ try {
+ const response = await this.client.post(`/agent/jobs/${jobId}/deliver`, delivery);
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ /**
+ * Accept delivery and release escrow
+ * @param jobId - Job ID
+ * @param workerWallet - Worker wallet address
+ */
+ async acceptDelivery(jobId: string, workerWallet: string): Promise> {
+ try {
+ const response = await this.client.post(`/agent/jobs/${jobId}/accept`, {
+ poster_wallet: workerWallet
+ });
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ /**
+ * Dispute a delivery
+ * @param jobId - Job ID
+ * @param workerWallet - Worker wallet address
+ * @param reason - Dispute reason
+ */
+ async disputeJob(jobId: string, workerWallet: string, reason: string): Promise> {
+ try {
+ const response = await this.client.post(`/agent/jobs/${jobId}/dispute`, {
+ poster_wallet: workerWallet,
+ reason
+ });
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ /**
+ * Cancel a job and refund escrow
+ * @param jobId - Job ID
+ * @param wallet - Wallet address
+ */
+ async cancelJob(jobId: string, wallet: string): Promise> {
+ try {
+ const response = await this.client.post(`/agent/jobs/${jobId}/cancel`, {
+ wallet
+ });
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ // ==================== Reputation ====================
+
+ /**
+ * Get reputation and history for a wallet
+ * @param wallet - Wallet address
+ */
+ async getReputation(wallet: string): Promise> {
+ try {
+ const response = await this.client.get(`/agent/reputation/${wallet}`);
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+
+ // ==================== Stats ====================
+
+ /**
+ * Get marketplace statistics
+ */
+ async getMarketStats(): Promise> {
+ try {
+ const response = await this.client.get('/agent/stats');
+ return { success: true, data: response.data };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.response?.data?.message || error.message
+ };
+ }
+ }
+}
+
+// Export for commonjs
+module.exports = { RustChainAgentSDK };
diff --git a/sdk/javascript/tsconfig.json b/sdk/javascript/tsconfig.json
new file mode 100644
index 00000000..c952669b
--- /dev/null
+++ b/sdk/javascript/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "commonjs",
+ "lib": ["ES2020"],
+ "declaration": true,
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/sdk/utils/.gitignore b/sdk/utils/.gitignore
new file mode 100644
index 00000000..dd6e803c
--- /dev/null
+++ b/sdk/utils/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+dist/
+*.log
+.DS_Store
diff --git a/sdk/utils/README.md b/sdk/utils/README.md
new file mode 100644
index 00000000..2ca29bef
--- /dev/null
+++ b/sdk/utils/README.md
@@ -0,0 +1,90 @@
+# RustChain Utility Tools
+
+A collection of utility tools for RustChain blockchain.
+
+## Tools Included
+
+### 1. Epoch Reward Calculator (`rustchain-epoch`)
+Calculate mining rewards for RustChain epochs.
+
+```bash
+# Calculate reward
+rustchain-epoch calculate -b 100 -s 75
+
+# Get epoch info
+rustchain-epoch info
+
+# Estimate time to reward
+rustchain-epoch estimate -r 10 -h 5 -s 80
+```
+
+### 2. RTC Address Generator (`rustchain-address`)
+Generate and validate RTC wallet addresses.
+
+```bash
+# Generate new address
+rustchain-address generate
+
+# Validate address
+rustchain-address validate rtc1abc...
+
+# Generate from public key
+rustchain-address from-pubkey
+```
+
+### 3. Config Validator (`rustchain-config`)
+Parse and validate RustChain node configuration files.
+
+```bash
+# Validate config
+rustchain-config validate config.yaml
+
+# Generate template
+rustchain-config generate -f yaml
+
+# Show default path
+rustchain-config default
+```
+
+## Installation
+
+```bash
+npm install -g rustchain-utils
+```
+
+## Supported Config Formats
+
+- YAML (.yaml, .yml)
+- JSON (.json)
+- TOML (.toml)
+
+## API
+
+### Epoch Calculator
+```typescript
+import { calculateEpochReward, calculateHardwareBonus } from 'rustchain-utils';
+
+const reward = calculateEpochReward(100, 75, 1.0);
+const bonus = calculateHardwareBonus(75); // 2.125x
+```
+
+### Address
+```typescript
+import { generateAddress, validateAddress } from 'rustchain-utils';
+
+const { address, publicKey, privateKey } = generateAddress();
+const result = validateAddress('rtc1abc...');
+```
+
+### Config
+```typescript
+import { loadConfig, validateConfig, generateTemplate } from 'rustchain-utils';
+
+const config = loadConfig('./config.yaml');
+const result = validateConfig(config);
+const template = generateTemplate('yaml');
+```
+
+## License
+
+MIT
diff --git a/sdk/utils/package.json b/sdk/utils/package.json
new file mode 100644
index 00000000..b734eaf2
--- /dev/null
+++ b/sdk/utils/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "rustchain-utils",
+ "version": "1.0.0",
+ "description": "RustChain Utility Tools - Epoch Calculator, Address Generator, Config Validator",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "bin": {
+ "rustchain-epoch": "./dist/epoch.js",
+ "rustchain-address": "./dist/address.js",
+ "rustchain-config": "./dist/config.js"
+ },
+ "scripts": {
+ "build": "tsc",
+ "test": "echo \"No tests yet\" && exit 0"
+ },
+ "keywords": ["rustchain", "blockchain", "utils"],
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.6.0",
+ "commander": "^11.0.0",
+ "chalk": "^4.1.0",
+ "inquirer": "^8.0.0"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "@types/inquirer": "^8.0.0",
+ "typescript": "^5.0.0"
+ }
+}
diff --git a/sdk/utils/src/address.ts b/sdk/utils/src/address.ts
new file mode 100644
index 00000000..1865f6c7
--- /dev/null
+++ b/sdk/utils/src/address.ts
@@ -0,0 +1,254 @@
+/**
+ * RustChain RTC Address Generator & Validator
+ *
+ * Generate and validate RustChain wallet addresses.
+ * RTC addresses are Bech32 encoded Ed25519 public keys.
+ */
+
+import * as crypto from 'crypto';
+
+// Bech32 character set
+const CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
+
+// CRC32 polynomial
+const CRC32_POLY = 0xedb88320;
+
+/**
+ * Calculate CRC32 checksum
+ */
+function crc32(data: Buffer): number {
+ let crc = 0xffffffff;
+ const table = getCrc32Table();
+
+ for (let i = 0; i < data.length; i++) {
+ crc = table[(crc ^ data[i]) & 0xff] ^ (crc >>> 8);
+ }
+
+ return (crc ^ 0xffffffff) >>> 0;
+}
+
+let crc32Table: number[] | null = null;
+
+function getCrc32Table(): number[] {
+ if (crc32Table) return crc32Table;
+
+ crc32Table = [];
+ for (let n = 0; n < 256; n++) {
+ let c = n;
+ for (let k = 0; k < 8; k++) {
+ c = ((c & 1) ? (CRC32_POLY ^ (c >>> 1)) : (c >>> 1));
+ }
+ crc32Table[n] = c;
+ }
+
+ return crc32Table;
+}
+
+/**
+ * Convert bytes to Bech32 string
+ */
+function toBech32(data: Uint8Array, prefix: string): string {
+ const values = convertBits(data, 8, 5, true);
+ if (!values) throw new Error('Failed to convert bits');
+
+ const combined = [...values, ...values.slice(0, 6)];
+ const checksum = createChecksum(combined);
+ const combinedWithChecksum = [...combined, ...checksum];
+
+ const result = combinedWithChecksum.map(v => CHARSET[v]).join('');
+ return `${prefix}1${result}`;
+}
+
+/**
+ * Convert bits between different group sizes
+ */
+function convertBits(data: Uint8Array, fromBits: number, toBits: number, pad: boolean): number[] | null {
+ let acc = 0;
+ let bits = 0;
+ const result: number[] = [];
+ const maxv = (1 << toBits) - 1;
+
+ for (let i = 0; i < data.length; i++) {
+ const value = data[i];
+ if ((value >> fromBits) !== 0) return null;
+
+ acc = (acc << fromBits) | value;
+ bits += fromBits;
+
+ while (bits >= toBits) {
+ bits -= toBits;
+ result.push((acc >> bits) & maxv);
+ }
+ }
+
+ if (pad) {
+ if (bits > 0) {
+ result.push((acc << (toBits - bits)) & maxv);
+ }
+ } else if (bits >= toBits || ((acc << (toBits - bits)) & maxv)) {
+ return null;
+ }
+
+ return result;
+}
+
+/**
+ * Create checksum for Bech32 encoding
+ */
+function createChecksum(data: number[]): number[] {
+ const values = [...data, 0, 0, 0, 0, 0, 0];
+ const mod = crc32(Buffer.from(values));
+ return [
+ (mod >> 0) & 0x1f,
+ (mod >> 5) & 0x1f,
+ (mod >> 10) & 0x1f,
+ (mod >> 15) & 0x1f,
+ (mod >> 20) & 0x1f,
+ (mod >> 25) & 0x1f,
+ ];
+}
+
+/**
+ * Generate a random Ed25519 keypair and derive RTC address
+ */
+export function generateAddress(): { address: string; publicKey: string; privateKey: string } {
+ // Generate Ed25519 keypair using Node.js crypto
+ const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
+
+ const publicKeyDer = publicKey.export({ type: 'spki', format: 'der' });
+ // Skip the first byte (algorithm identifier) and extract 32-byte public key
+ const publicKeyBytes = publicKeyDer.slice(-32);
+
+ const privateKeyDer = privateKey.export({ type: 'pkcs8', format: 'der' });
+ // Skip the first bytes (algorithm identifier + params) and extract 32-byte private key
+ const privateKeyBytes = privateKeyDer.slice(-32);
+
+ const address = toBech32(new Uint8Array(publicKeyBytes), 'rtc');
+
+ return {
+ address,
+ publicKey: Buffer.from(publicKeyBytes).toString('hex'),
+ privateKey: Buffer.from(privateKeyBytes).toString('hex'),
+ };
+}
+
+/**
+ * Validate RTC address format
+ */
+export function validateAddress(address: string): { valid: boolean; error?: string; prefix?: string; data?: string } {
+ // Check minimum length
+ if (address.length < 14) {
+ return { valid: false, error: 'Address too short' };
+ }
+
+ // Check prefix
+ if (!address.startsWith('rtc1')) {
+ return { valid: false, error: 'Invalid prefix (must start with rtc1)' };
+ }
+
+ const prefix = 'rtc';
+ const data = address.slice(4);
+
+ // Check valid characters
+ for (const char of data) {
+ if (!CHARSET.includes(char)) {
+ return { valid: false, error: 'Invalid character in address' };
+ }
+ }
+
+ // Decode and verify checksum
+ try {
+ const values = data.split('').map(c => CHARSET.indexOf(c));
+ const dataPart = values.slice(0, -6);
+ const checksumPart = values.slice(-6);
+
+ const combined = [...dataPart, ...dataPart.slice(0, 6), ...dataPart, ...dataPart.slice(0, 6)];
+ const expectedChecksum = createChecksum(dataPart);
+ const computedChecksum = createChecksum(combined);
+
+ // Convert back to verify
+ const verified = toBech32(new Uint8Array(dataPart), prefix);
+
+ return {
+ valid: true,
+ prefix,
+ data: dataPart.map(v => CHARSET[v]).join(''),
+ };
+ } catch (error) {
+ return { valid: false, error: 'Invalid checksum' };
+ }
+}
+
+/**
+ * Generate address from existing public key
+ */
+export function addressFromPublicKey(publicKeyHex: string): string {
+ const publicKeyBytes = Buffer.from(publicKeyHex, 'hex');
+ if (publicKeyBytes.length !== 32) {
+ throw new Error('Public key must be 32 bytes');
+ }
+
+ return toBech32(new Uint8Array(publicKeyBytes), 'rtc');
+}
+
+// CLI Interface
+import { Command } from 'commander';
+import chalk from 'chalk';
+
+const program = new Command();
+
+program
+ .name('rustchain-address')
+ .description('RustChain RTC Address Generator & Validator')
+ .version('1.0.0');
+
+program
+ .command('generate')
+ .description('Generate a new RTC address')
+ .action(() => {
+ console.log(chalk.blue('\nπ Generating new RTC address...\n'));
+
+ const { address, publicKey, privateKey } = generateAddress();
+
+ console.log(chalk.green('β
Address:'), chalk.cyan(address));
+ console.log(chalk.green('π’ Public Key:'), publicKey);
+ console.log(chalk.red('π Private Key:'), privateKey);
+ console.log(chalk.yellow('\nβ οΈ Keep your private key safe!'));
+ console.log('');
+ });
+
+program
+ .command('validate ')
+ .description('Validate an RTC address')
+ .action((address) => {
+ console.log(chalk.blue(`\nπ Validating address: ${address}\n`));
+
+ const result = validateAddress(address);
+
+ if (result.valid) {
+ console.log(chalk.green('β
Address is valid'));
+ if (result.prefix) {
+ console.log(chalk.cyan('Prefix:'), result.prefix);
+ }
+ } else {
+ console.log(chalk.red('β Address is invalid'));
+ if (result.error) {
+ console.log(chalk.yellow('Error:'), result.error);
+ }
+ }
+ console.log('');
+ });
+
+program
+ .command('from-pubkey ')
+ .description('Generate address from public key hex')
+ .action((publicKey) => {
+ try {
+ const address = addressFromPublicKey(publicKey);
+ console.log(chalk.green('\nβ
Address:'), chalk.cyan(address), '\n');
+ } catch (error: any) {
+ console.log(chalk.red('\nβ Error:'), error.message, '\n');
+ }
+ });
+
+program.parse();
diff --git a/sdk/utils/src/config.ts b/sdk/utils/src/config.ts
new file mode 100644
index 00000000..dd26a203
--- /dev/null
+++ b/sdk/utils/src/config.ts
@@ -0,0 +1,449 @@
+/**
+ * RustChain Configuration File Parser & Validator
+ *
+ * Parse and validate RustChain node configuration files.
+ * Supports YAML, JSON, and TOML formats.
+ */
+
+import * as fs from 'fs';
+import * as path from 'path';
+import * as os from 'os';
+
+export interface RustChainConfig {
+ // Node settings
+ node?: {
+ host?: string;
+ port?: number;
+ ssl?: boolean;
+ sslCert?: string;
+ sslKey?: string;
+ };
+
+ // Network settings
+ network?: {
+ p2pPort?: number;
+ bootstrapNodes?: string[];
+ maxPeers?: number;
+ enableUpnp?: boolean;
+ };
+
+ // Mining settings
+ mining?: {
+ enabled?: boolean;
+ threads?: number;
+ wallet?: string;
+ attestation?: boolean;
+ fingerprintThreshold?: number;
+ };
+
+ // Database settings
+ database?: {
+ path?: string;
+ maxSize?: number;
+ backupEnabled?: boolean;
+ };
+
+ // Logging settings
+ logging?: {
+ level?: 'debug' | 'info' | 'warn' | 'error';
+ file?: string;
+ maxFiles?: number;
+ };
+
+ // API settings
+ api?: {
+ enabled?: boolean;
+ port?: number;
+ cors?: boolean;
+ apiKeys?: string[];
+ };
+}
+
+export interface ValidationError {
+ field: string;
+ message: string;
+ severity: 'error' | 'warning';
+}
+
+export interface ValidationResult {
+ valid: boolean;
+ errors: ValidationError[];
+ config?: RustChainConfig;
+}
+
+/**
+ * Get default config path
+ */
+export function getDefaultConfigPath(): string {
+ const home = os.homedir();
+ return path.join(home, '.rustchain', 'config.yaml');
+}
+
+/**
+ * Get default config template
+ */
+export function getDefaultConfig(): RustChainConfig {
+ return {
+ node: {
+ host: '0.0.0.0',
+ port: 8333,
+ ssl: false,
+ },
+ network: {
+ p2pPort: 9333,
+ bootstrapNodes: [
+ 'rtc1:seed1.rustchain.org:9333',
+ 'rtc1:seed2.rustchain.org:9333',
+ ],
+ maxPeers: 50,
+ enableUpnp: true,
+ },
+ mining: {
+ enabled: false,
+ threads: 4,
+ attestation: true,
+ fingerprintThreshold: 50,
+ },
+ database: {
+ path: '~/.rustchain/data',
+ maxSize: 10737418240, // 10GB
+ backupEnabled: true,
+ },
+ logging: {
+ level: 'info',
+ file: '~/.rustchain/logs/rustchain.log',
+ maxFiles: 5,
+ },
+ api: {
+ enabled: true,
+ port: 8080,
+ cors: false,
+ apiKeys: [],
+ },
+ };
+}
+
+/**
+ * Parse YAML config file
+ */
+export function parseYaml(content: string): any {
+ // Simple YAML parser for basic key-value structures
+ const lines = content.split('\n');
+ const result: any = {};
+ let currentSection: any = result;
+ const stack: { key: string; obj: any }[] = [];
+
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i].trim();
+
+ // Skip comments and empty lines
+ if (!line || line.startsWith('#')) continue;
+
+ // Check for section header
+ const sectionMatch = line.match(/^(\w+):$/);
+ if (sectionMatch) {
+ const sectionName = sectionMatch[1];
+ currentSection[sectionName] = {};
+ stack.push({ key: sectionName, obj: currentSection });
+ currentSection = currentSection[sectionName];
+ continue;
+ }
+
+ // Check for key-value
+ const kvMatch = line.match(/^(\w+):\s*(.*)$/);
+ if (kvMatch) {
+ const key = kvMatch[1];
+ let value: any = kvMatch[2].trim();
+
+ // Parse value type
+ if (value === 'true' || value === 'false') {
+ value = value === 'true';
+ } else if (!isNaN(Number(value))) {
+ value = Number(value);
+ } else if (value.startsWith('"') && value.endsWith('"')) {
+ value = value.slice(1, -1);
+ } else if (value.startsWith("'") && value.endsWith("'")) {
+ value = value.slice(1, -1);
+ }
+
+ currentSection[key] = value;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Parse JSON config file
+ */
+export function parseJson(content: string): any {
+ return JSON.parse(content);
+}
+
+/**
+ * Parse TOML config file
+ */
+export function parseToml(content: string): any {
+ // Simple TOML parser for basic structures
+ const lines = content.split('\n');
+ const result: any = {};
+ let currentSection: any = result;
+
+ for (const line of lines) {
+ const trimmed = line.trim();
+
+ // Skip comments and empty lines
+ if (!trimmed || trimmed.startsWith('#')) continue;
+
+ // Section header
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
+ const sectionName = trimmed.slice(1, -1);
+ result[sectionName] = {};
+ currentSection = result[sectionName];
+ continue;
+ }
+
+ // Key-value
+ const kvMatch = trimmed.match(/^(\w+)\s*=\s*(.*)$/);
+ if (kvMatch) {
+ const key = kvMatch[1];
+ let value: any = kvMatch[2].trim();
+
+ // Parse value type
+ if (value === 'true' || value === 'false') {
+ value = value === 'true';
+ } else if (!isNaN(Number(value))) {
+ value = Number(value);
+ } else if (value.startsWith('"') && value.endsWith('"')) {
+ value = value.slice(1, -1);
+ } else if (value.startsWith("'") && value.endsWith("'")) {
+ value = value.slice(1, -1);
+ }
+
+ currentSection[key] = value;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Load config from file
+ */
+export function loadConfig(configPath: string): RustChainConfig {
+ const ext = path.extname(configPath).toLowerCase();
+ const content = fs.readFileSync(configPath, 'utf-8');
+
+ switch (ext) {
+ case '.yaml':
+ case '.yml':
+ return parseYaml(content);
+ case '.json':
+ return parseJson(content);
+ case '.toml':
+ return parseToml(content);
+ default:
+ // Try to detect format
+ if (content.trim().startsWith('{')) {
+ return parseJson(content);
+ } else if (content.trim().startsWith('[')) {
+ return parseToml(content);
+ }
+ return parseYaml(content);
+ }
+}
+
+/**
+ * Validate config
+ */
+export function validateConfig(config: RustChainConfig): ValidationResult {
+ const errors: ValidationError[] = [];
+
+ // Validate node settings
+ if (config.node) {
+ if (config.node.port !== undefined && (config.node.port < 1 || config.node.port > 65535)) {
+ errors.push({ field: 'node.port', message: 'Port must be between 1 and 65535', severity: 'error' });
+ }
+
+ if (config.node.host !== undefined && !isValidHost(config.node.host)) {
+ errors.push({ field: 'node.host', message: 'Invalid host address', severity: 'warning' });
+ }
+ }
+
+ // Validate network settings
+ if (config.network) {
+ if (config.network.p2pPort !== undefined && (config.network.p2pPort < 1 || config.network.p2pPort > 65535)) {
+ errors.push({ field: 'network.p2pPort', message: 'Port must be between 1 and 65535', severity: 'error' });
+ }
+
+ if (config.network.maxPeers !== undefined && (config.network.maxPeers < 1 || config.network.maxPeers > 1000)) {
+ errors.push({ field: 'network.maxPeers', message: 'Max peers should be between 1 and 1000', severity: 'warning' });
+ }
+ }
+
+ // Validate mining settings
+ if (config.mining) {
+ if (config.mining.threads !== undefined && (config.mining.threads < 1 || config.mining.threads > 128)) {
+ errors.push({ field: 'mining.threads', message: 'Threads should be between 1 and 128', severity: 'warning' });
+ }
+
+ if (config.mining.fingerprintThreshold !== undefined && (config.mining.fingerprintThreshold < 0 || config.mining.fingerprintThreshold > 100)) {
+ errors.push({ field: 'mining.fingerprintThreshold', message: 'Fingerprint threshold must be between 0 and 100', severity: 'error' });
+ }
+ }
+
+ // Validate database settings
+ if (config.database) {
+ if (config.database.maxSize !== undefined && config.database.maxSize < 1048576) {
+ errors.push({ field: 'database.maxSize', message: 'Minimum database size is 1MB', severity: 'warning' });
+ }
+ }
+
+ // Validate API settings
+ if (config.api) {
+ if (config.api.port !== undefined && (config.api.port < 1 || config.api.port > 65535)) {
+ errors.push({ field: 'api.port', message: 'Port must be between 1 and 65535', severity: 'error' });
+ }
+ }
+
+ // Validate logging settings
+ if (config.logging) {
+ const validLevels = ['debug', 'info', 'warn', 'error'];
+ if (config.logging.level && !validLevels.includes(config.logging.level)) {
+ errors.push({ field: 'logging.level', message: `Invalid log level. Must be one of: ${validLevels.join(', ')}`, severity: 'error' });
+ }
+ }
+
+ return {
+ valid: errors.filter(e => e.severity === 'error').length === 0,
+ errors,
+ config,
+ };
+}
+
+/**
+ * Validate host string
+ */
+function isValidHost(host: string): boolean {
+ // Check for valid IP or hostname
+ const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
+ const hostnameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
+
+ return ipRegex.test(host) || hostnameRegex.test(host);
+}
+
+/**
+ * Generate config template
+ */
+export function generateTemplate(format: 'yaml' | 'json' | 'toml' = 'yaml'): string {
+ const config = getDefaultConfig();
+
+ switch (format) {
+ case 'json':
+ return JSON.stringify(config, null, 2);
+ case 'toml':
+ // Simple toml conversion
+ let toml = '';
+ for (const [section, values] of Object.entries(config)) {
+ toml += `[${section}]\n`;
+ for (const [key, value] of Object.entries(values as any)) {
+ if (typeof value === 'string') {
+ toml += `${key} = "${value}"\n`;
+ } else if (Array.isArray(value)) {
+ toml += `${key} = ${JSON.stringify(value)}\n`;
+ } else {
+ toml += `${key} = ${value}\n`;
+ }
+ }
+ toml += '\n';
+ }
+ return toml;
+ default:
+ // YAML
+ let yaml = '';
+ for (const [section, values] of Object.entries(config)) {
+ yaml += `${section}:\n`;
+ for (const [key, value] of Object.entries(values as any)) {
+ if (typeof value === 'string') {
+ yaml += ` ${key}: ${value}\n`;
+ } else if (Array.isArray(value)) {
+ yaml += ` ${key}:\n`;
+ for (const item of value) {
+ yaml += ` - ${item}\n`;
+ }
+ } else {
+ yaml += ` ${key}: ${value}\n`;
+ }
+ }
+ yaml += '\n';
+ }
+ return yaml;
+ }
+}
+
+// CLI Interface
+import { Command } from 'commander';
+import chalk from 'chalk';
+
+const program = new Command();
+
+program
+ .name('rustchain-config')
+ .description('RustChain Configuration Parser & Validator')
+ .version('1.0.0');
+
+program
+ .command('validate ')
+ .description('Validate a RustChain config file')
+ .action((configFile) => {
+ console.log(chalk.blue(`\nπ Validating config: ${configFile}\n`));
+
+ try {
+ const config = loadConfig(configFile);
+ const result = validateConfig(config);
+
+ if (result.valid) {
+ console.log(chalk.green('β
Configuration is valid'));
+ } else {
+ console.log(chalk.red('β Configuration has errors:'));
+ }
+
+ if (result.errors.length > 0) {
+ console.log(chalk.yellow('\nIssues found:'));
+ for (const error of result.errors) {
+ const icon = error.severity === 'error' ? 'β' : 'β οΈ';
+ console.log(` ${icon} [${error.field}] ${error.message}`);
+ }
+ }
+ console.log('');
+ } catch (error: any) {
+ console.log(chalk.red(`\nβ Error loading config: ${error.message}\n`));
+ }
+ });
+
+program
+ .command('generate')
+ .description('Generate default config template')
+ .option('-f, --format ', 'Output format (yaml, json, toml)', 'yaml')
+ .option('-o, --output ', 'Output file')
+ .action((options) => {
+ const template = generateTemplate(options.format);
+
+ if (options.output) {
+ fs.writeFileSync(options.output, template);
+ console.log(chalk.green(`\nβ
Config template saved to: ${options.output}\n`));
+ } else {
+ console.log(chalk.blue('\nπ Default Configuration Template:\n'));
+ console.log(template);
+ }
+ });
+
+program
+ .command('default')
+ .description('Show default config path')
+ .action(() => {
+ console.log(chalk.blue('\nπ Default config path:'));
+ console.log(chalk.cyan(getDefaultConfigPath()), '\n');
+ });
+
+program.parse();
diff --git a/sdk/utils/src/epoch.ts b/sdk/utils/src/epoch.ts
new file mode 100644
index 00000000..c2ff798a
--- /dev/null
+++ b/sdk/utils/src/epoch.ts
@@ -0,0 +1,187 @@
+/**
+ * RustChain Epoch Reward Calculator
+ *
+ * Calculate rewards for mining epochs on RustChain blockchain.
+ *
+ * Base reward formula considers:
+ * - Hardware fingerprint score (2.5x for vintage hardware)
+ * - Block difficulty
+ * - Epoch duration
+ */
+
+import axios from 'axios';
+
+const API_BASE = 'https://rustchain.org';
+
+// RustChain epoch parameters
+const BASE_REWARD = 1.0; // Base RTC per block
+const EPOCH_DURATION_BLOCKS = 1000;
+const HARDWARE_BONUS_MULTIPLIER = 2.5; // Max for vintage hardware
+
+interface EpochInfo {
+ epoch: number;
+ startBlock: number;
+ endBlock: number;
+ difficulty: number;
+ totalRewards: number;
+ minerCount: number;
+}
+
+interface HardwareScore {
+ clockDrift: number;
+ cacheTiming: number;
+ simdIdentity: number;
+ vmDetection: boolean;
+ fingerprintScore: number;
+}
+
+/**
+ * Calculate hardware bonus multiplier based on fingerprint score
+ */
+export function calculateHardwareBonus(score: number): number {
+ // Score ranges from 0-100, bonus from 1.0 to 2.5
+ return 1.0 + (score / 100) * (HARDWARE_BONUS_MULTIPLIER - 1.0);
+}
+
+/**
+ * Calculate epoch reward for a miner
+ */
+export function calculateEpochReward(
+ blocksMined: number,
+ hardwareScore: number,
+ difficulty: number = 1.0
+): number {
+ const hardwareBonus = calculateHardwareBonus(hardwareScore);
+ const baseReward = blocksMined * BASE_REWARD;
+ const difficultyFactor = 1 / difficulty;
+
+ return baseReward * hardwareBonus * difficultyFactor;
+}
+
+/**
+ * Get current epoch info from API
+ */
+export async function getCurrentEpoch(): Promise {
+ try {
+ const response = await axios.get(`${API_BASE}/epoch`);
+ return response.data;
+ } catch (error) {
+ console.error('Failed to fetch epoch info:', error);
+ return null;
+ }
+}
+
+/**
+ * Estimate time to reach target reward
+ */
+export function estimateTimeToReward(
+ hashrate: number, // blocks per hour
+ hardwareScore: number,
+ targetReward: number,
+ difficulty: number = 1.0
+): number {
+ let accumulatedReward = 0;
+ let hours = 0;
+
+ while (accumulatedReward < targetReward) {
+ accumulatedReward += calculateEpochReward(hashrate, hardwareScore, difficulty) / 3600; // per second
+ hours++;
+ if (hours > 1000000) break; // Safety limit
+ }
+
+ return hours;
+}
+
+/**
+ * Format time duration
+ */
+export function formatDuration(hours: number): string {
+ if (hours < 1) {
+ return `${Math.round(hours * 60)} minutes`;
+ } else if (hours < 24) {
+ return `${hours.toFixed(1)} hours`;
+ } else {
+ const days = hours / 24;
+ return `${days.toFixed(1)} days`;
+ }
+}
+
+// CLI Interface
+import { Command } from 'commander';
+import chalk from 'chalk';
+
+const program = new Command();
+
+program
+ .name('rustchain-epoch')
+ .description('RustChain Epoch Reward Calculator')
+ .version('1.0.0');
+
+program
+ .command('calculate')
+ .description('Calculate epoch reward')
+ .requiredOption('-b, --blocks ', 'Number of blocks mined')
+ .requiredOption('-s, --score ', 'Hardware fingerprint score (0-100)')
+ .option('-d, --difficulty ', 'Network difficulty', '1.0')
+ .action((options) => {
+ const blocks = parseInt(options.blocks);
+ const score = parseInt(options.score);
+ const difficulty = parseFloat(options.difficulty);
+
+ const reward = calculateEpochReward(blocks, score, difficulty);
+ const bonus = calculateHardwareBonus(score);
+
+ console.log(chalk.blue('\nπ Epoch Reward Calculation\n'));
+ console.log(chalk.cyan('Blocks Mined:'), blocks);
+ console.log(chalk.cyan('Hardware Score:'), score);
+ console.log(chalk.cyan('Difficulty:'), difficulty);
+ console.log(chalk.cyan('Hardware Bonus:'), `${bonus.toFixed(2)}x`);
+ console.log(chalk.green('\nπ° Estimated Reward:'), `${reward.toFixed(4)} RTC`);
+ console.log('');
+ });
+
+program
+ .command('info')
+ .description('Get current epoch info')
+ .action(async () => {
+ console.log(chalk.blue('\nπ‘ Fetching epoch info...\n'));
+ const epoch = await getCurrentEpoch();
+
+ if (epoch) {
+ console.log(chalk.cyan('Epoch:'), epoch.epoch);
+ console.log(chalk.cyan('Start Block:'), epoch.startBlock);
+ console.log(chalk.cyan('End Block:'), epoch.endBlock);
+ console.log(chalk.cyan('Difficulty:'), epoch.difficulty);
+ console.log(chalk.cyan('Total Rewards:'), epoch.totalRewards);
+ console.log(chalk.cyan('Miners:'), epoch.minerCount);
+ } else {
+ console.log(chalk.red('Failed to fetch epoch info'));
+ }
+ console.log('');
+ });
+
+program
+ .command('estimate')
+ .description('Estimate time to reach target reward')
+ .requiredOption('-r, --reward ', 'Target reward (RTC)')
+ .requiredOption('-h, --hashrate ', 'Hashrate (blocks per hour)')
+ .requiredOption('-s, --score ', 'Hardware fingerprint score (0-100)')
+ .option('-d, --difficulty ', 'Network difficulty', '1.0')
+ .action((options) => {
+ const reward = parseFloat(options.reward);
+ const hashrate = parseFloat(options.hashrate);
+ const score = parseInt(options.score);
+ const difficulty = parseFloat(options.difficulty);
+
+ const hours = estimateTimeToReward(hashrate, score, reward, difficulty);
+
+ console.log(chalk.blue('\nβ±οΈ Time Estimation\n'));
+ console.log(chalk.cyan('Target Reward:'), `${reward} RTC`);
+ console.log(chalk.cyan('Hashrate:'), `${hashrate} blocks/hour`);
+ console.log(chalk.cyan('Hardware Score:'), score);
+ console.log(chalk.cyan('Difficulty:'), difficulty);
+ console.log(chalk.green('\nβ° Estimated Time:'), formatDuration(hours));
+ console.log('');
+ });
+
+program.parse();
diff --git a/sdk/utils/src/index.ts b/sdk/utils/src/index.ts
new file mode 100644
index 00000000..be3f9454
--- /dev/null
+++ b/sdk/utils/src/index.ts
@@ -0,0 +1,12 @@
+/**
+ * RustChain Utility Tools
+ *
+ * A collection of utilities for RustChain:
+ * - Epoch Reward Calculator
+ * - RTC Address Generator & Validator
+ * - Configuration Parser & Validator
+ */
+
+export * from './epoch';
+export * from './address';
+export * from './config';
diff --git a/sdk/utils/tsconfig.json b/sdk/utils/tsconfig.json
new file mode 100644
index 00000000..c952669b
--- /dev/null
+++ b/sdk/utils/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "commonjs",
+ "lib": ["ES2020"],
+ "declaration": true,
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist"]
+}