Merge dependency updates from GitHub

- Updated black from 24.3.0 to 26.3.1
- Kept ruff at 0.15.7 (our updated version)
- All other dependency updates already applied
This commit is contained in:
2026-03-26 08:31:46 +01:00
497 changed files with 11695 additions and 69836 deletions

145
.github/workflows/gpu-benchmark.yml vendored Normal file
View File

@@ -0,0 +1,145 @@
name: GPU Benchmark CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
# Run benchmarks daily at 2 AM UTC
- cron: '0 2 * * *'
jobs:
gpu-benchmark:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.13]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
python3-dev \
pkg-config \
libnvidia-compute-515 \
cuda-toolkit-12-2 \
nvidia-driver-515
- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install -e .
pip install pytest pytest-benchmark torch torchvision torchaudio
pip install cupy-cuda12x
pip install nvidia-ml-py3
- name: Verify GPU availability
run: |
python -c "
import torch
print(f'PyTorch version: {torch.__version__}')
print(f'CUDA available: {torch.cuda.is_available()}')
if torch.cuda.is_available():
print(f'CUDA version: {torch.version.cuda}')
print(f'GPU count: {torch.cuda.device_count()}')
print(f'GPU name: {torch.cuda.get_device_name(0)}')
"
- name: Run GPU benchmarks
run: |
python -m pytest dev/gpu/test_gpu_performance.py \
--benchmark-only \
--benchmark-json=benchmark_results.json \
--benchmark-sort=mean \
-v
- name: Generate benchmark report
run: |
python dev/gpu/generate_benchmark_report.py \
--input benchmark_results.json \
--output benchmark_report.html \
--history-file benchmark_history.json
- name: Upload benchmark results
uses: actions/upload-artifact@v3
with:
name: benchmark-results-${{ matrix.python-version }}
path: |
benchmark_results.json
benchmark_report.html
benchmark_history.json
retention-days: 30
- name: Compare with baseline
run: |
python dev/gpu/compare_benchmarks.py \
--current benchmark_results.json \
--baseline .github/baselines/gpu_baseline.json \
--threshold 5.0 \
--output comparison_report.json
- name: Comment PR with results
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
try {
const results = JSON.parse(fs.readFileSync('comparison_report.json', 'utf8'));
const comment = `
## 🚀 GPU Benchmark Results
**Performance Summary:**
- **Mean Performance**: ${results.mean_performance.toFixed(2)} ops/sec
- **Performance Change**: ${results.performance_change > 0 ? '+' : ''}${results.performance_change.toFixed(2)}%
- **Status**: ${results.status}
**Key Metrics:**
${results.metrics.map(m => `- **${m.name}**: ${m.value.toFixed(2)} ops/sec (${m.change > 0 ? '+' : ''}${m.change.toFixed(2)}%)`).join('\n')}
${results.regressions.length > 0 ? '⚠️ **Performance Regressions Detected**' : '✅ **No Performance Regressions**'}
[View detailed report](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
} catch (error) {
console.log('Could not generate benchmark comment:', error.message);
}
- name: Update benchmark history
run: |
python dev/gpu/update_benchmark_history.py \
--results benchmark_results.json \
--history-file .github/baselines/benchmark_history.json \
--max-entries 100
- name: Fail on performance regression
run: |
python dev/gpu/check_performance_regression.py \
--results benchmark_results.json \
--baseline .github/baselines/gpu_baseline.json \
--threshold 10.0

View File

@@ -43,7 +43,7 @@ jobs:
bandit -r ${{ matrix.directory }} -f text -o bandit-report-${{ matrix.directory }}.txt bandit -r ${{ matrix.directory }} -f text -o bandit-report-${{ matrix.directory }}.txt
- name: Upload Bandit reports - name: Upload Bandit reports
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v7
with: with:
name: bandit-report-${{ matrix.directory }} name: bandit-report-${{ matrix.directory }}
path: | path: |
@@ -53,7 +53,7 @@ jobs:
- name: Comment PR with Bandit findings - name: Comment PR with Bandit findings
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
uses: actions/github-script@v7 uses: actions/github-script@v8
with: with:
script: | script: |
const fs = require('fs'); const fs = require('fs');
@@ -132,7 +132,7 @@ jobs:
cd ../.. && cd website && npm audit --json > ../npm-audit-website.json || true cd ../.. && cd website && npm audit --json > ../npm-audit-website.json || true
- name: Upload dependency reports - name: Upload dependency reports
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v7
with: with:
name: dependency-security-reports name: dependency-security-reports
path: | path: |
@@ -178,7 +178,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Run OSSF Scorecard - name: Run OSSF Scorecard
uses: ossf/scorecard-action@v2.3.3 uses: ossf/scorecard-action@v2.4.3
with: with:
results_file: results.sarif results_file: results.sarif
results_format: sarif results_format: sarif
@@ -233,7 +233,7 @@ jobs:
echo "4. Schedule regular security reviews" >> security-summary.md echo "4. Schedule regular security reviews" >> security-summary.md
- name: Upload security summary - name: Upload security summary
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v7
with: with:
name: security-summary name: security-summary
path: security-summary.md path: security-summary.md
@@ -241,7 +241,7 @@ jobs:
- name: Comment PR with security summary - name: Comment PR with security summary
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
uses: actions/github-script@v7 uses: actions/github-script@v8
with: with:
script: | script: |
const fs = require('fs'); const fs = require('fs');

165
.gitignore vendored
View File

@@ -1,4 +1,6 @@
# AITBC Monorepo ignore rules # AITBC Monorepo ignore rules
# Updated: 2026-03-18 - Security fixes for hardcoded passwords
# Development files organized into dev/ subdirectories
# =================== # ===================
# Python # Python
@@ -96,13 +98,27 @@ target/
*.dylib *.dylib
# =================== # ===================
# Node.js # Secrets & Credentials (CRITICAL SECURITY)
# ===================
# =================== # ===================
node_modules/ node_modules/
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
# Password files (NEVER commit these)
*.password
*.pass
.password.*
keystore/.password
keystore/.password.*
# Private keys and sensitive files
*_private_key.txt
*_private_key.json
private_key.*
*.private
# =================== # ===================
# Backup Files (organized) # Backup Files (organized)
# =================== # ===================
@@ -151,8 +167,149 @@ home/genesis_wallet.json
home/miner/miner_wallet.json home/miner/miner_wallet.json
# =================== # ===================
# Test Results # Project Specific
# =================== # ===================
test-results/ # Coordinator database
**/test-results/ apps/coordinator-api/src/*.db
# Blockchain node data
apps/blockchain-node/data/
# Explorer build artifacts
apps/explorer-web/dist/
# Solidity build artifacts
packages/solidity/aitbc-token/typechain-types/
packages/solidity/aitbc-token/artifacts/
packages/solidity/aitbc-token/cache/
# Local test fixtures and E2E testing
tests/e2e/fixtures/home/**/.aitbc/cache/
tests/e2e/fixtures/home/**/.aitbc/logs/
tests/e2e/fixtures/home/**/.aitbc/tmp/
tests/e2e/fixtures/home/**/.aitbc/*.log
tests/e2e/fixtures/home/**/.aitbc/*.pid
tests/e2e/fixtures/home/**/.aitbc/*.sock
# Keep fixture structure but exclude generated content
!tests/e2e/fixtures/home/
!tests/e2e/fixtures/home/**/
!tests/e2e/fixtures/home/**/.aitbc/
!tests/e2e/fixtures/home/**/.aitbc/wallets/
!tests/e2e/fixtures/home/**/.aitbc/config/
# Local test data
tests/fixtures/generated/
# GPU miner local configs
scripts/gpu/*.local.py
# Deployment secrets (CRITICAL SECURITY)
scripts/deploy/*.secret.*
infra/nginx/*.local.conf
# ===================
# Documentation
# ===================
# Infrastructure docs (contains sensitive network info)
docs/infrastructure.md
# Workflow files (personal, change frequently)
docs/1_project/3_currenttask.md
docs/1_project/4_currentissue.md
# ===================
# Website (local deployment details)
# ===================
website/README.md
website/aitbc-proxy.conf
# ===================
# Local Config & Secrets
# ===================
.aitbc.yaml
apps/coordinator-api/.env
# ===================
# Windsurf IDE (personal dev tooling)
# ===================
.windsurf/
# ===================
# Deploy Scripts (hardcoded local paths & IPs)
# ===================
scripts/deploy/*
!scripts/deploy/*.example
scripts/gpu/*
!scripts/gpu/*.example
scripts/service/*
# ===================
# Infra Configs (production IPs & secrets)
# ===================
infra/nginx/nginx-aitbc*.conf
infra/helm/values/prod/
infra/helm/values/prod.yaml
# ===================
# Node.js
# ===================
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Build artifacts
build/
dist/
target/
# System files
*.pid
*.seed
*.pid.lock
# Coverage reports
htmlcov/
.coverage
.coverage.*
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# Environments
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# ===================
# AITBC specific (CRITICAL SECURITY)
# ===================
data/
logs/
*.db
*.sqlite
wallet*.json
keystore/
certificates/
# Guardian contract databases (contain spending limits)
guardian_contracts/
*.guardian.db
# Multi-chain wallet data
.wallets/
.wallets/*
# Agent protocol data
.agent_data/
.agent_data/*

61
RELEASE_v0.2.2.md Normal file
View File

@@ -0,0 +1,61 @@
# AITBC v0.2.2 Release Notes
## 🎯 Overview
AITBC v0.2.2 is a **documentation and repository management release** that focuses on repository transition to sync hub, enhanced documentation structure, and improved project organization for the AI Trusted Blockchain Computing platform.
## 🚀 New Features
### <20> Documentation Enhancements
- **Hub Status Documentation**: Complete repository transition documentation
- **README Updates**: Hub-only warnings and improved project description
- **Documentation Cleanup**: Removed outdated v0.2.0 release notes
- **Project Organization**: Enhanced root directory structure
### 🔧 Repository Management
- **Sync Hub Transition**: Documentation for repository sync hub status
- **Warning System**: Hub-only warnings in README for clarity
- **Clean Documentation**: Streamlined documentation structure
- **Version Management**: Improved version tracking and cleanup
### <20> Project Structure
- **Root Organization**: Clean and professional project structure
- **Documentation Hierarchy**: Better organized documentation files
- **Maintenance Updates**: Simplified maintenance procedures
## 📊 Statistics
- **Total Commits**: 350+
- **Documentation Updates**: 8
- **Repository Enhancements**: 5
- **Cleanup Operations**: 3
## 🔗 Changes from v0.2.1
- Removed outdated v0.2.0 release notes file
- Removed Docker removal summary from README
- Improved project documentation structure
- Streamlined repository management
- Enhanced README clarity and organization
## 🚦 Migration Guide
1. Pull latest updates: `git pull`
2. Check README for updated project information
3. Verify documentation structure
4. Review updated release notes
## 🐛 Bug Fixes
- Fixed documentation inconsistencies
- Resolved version tracking issues
- Improved repository organization
## 🎯 What's Next
- Enhanced multi-chain support
- Advanced agent orchestration
- Performance optimizations
- Security enhancements
## 🙏 Acknowledgments
Special thanks to the AITBC community for contributions, testing, and feedback.
---
*Release Date: March 24, 2026*
*License: MIT*
*GitHub: https://github.com/oib/AITBC*

View File

@@ -64,7 +64,32 @@ const app = createApp({
formatTime(timestamp) { formatTime(timestamp) {
if (!timestamp) return '-' if (!timestamp) return '-'
return new Date(timestamp * 1000).toLocaleString()
// Handle ISO strings
if (typeof timestamp === 'string') {
try {
const date = new Date(timestamp)
return date.toLocaleString()
} catch (e) {
console.warn('Invalid timestamp format:', timestamp)
return '-'
}
}
// Handle numeric timestamps (could be seconds or milliseconds)
const numTimestamp = Number(timestamp)
if (isNaN(numTimestamp)) return '-'
// If timestamp is in seconds (typical Unix timestamp), convert to milliseconds
// If timestamp is already in milliseconds, use as-is
const msTimestamp = numTimestamp < 10000000000 ? numTimestamp * 1000 : numTimestamp
try {
return new Date(msTimestamp).toLocaleString()
} catch (e) {
console.warn('Invalid timestamp value:', timestamp)
return '-'
}
}, },
formatNumber(num) { formatNumber(num) {

View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. # This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand.
[[package]] [[package]]
name = "aiosqlite" name = "aiosqlite"
@@ -928,99 +928,86 @@ files = [
[[package]] [[package]]
name = "orjson" name = "orjson"
version = "3.11.5" version = "3.11.7"
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.10"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1"}, {file = "orjson-3.11.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174"},
{file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870"}, {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63c6e6738d7c3470ad01601e23376aa511e50e1f3931395b9f9c722406d1a67"},
{file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09"}, {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:043d3006b7d32c7e233b8cfb1f01c651013ea079e08dcef7189a29abd8befe11"},
{file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd"}, {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57036b27ac8a25d81112eb0cc9835cd4833c5b16e1467816adc0015f59e870dc"},
{file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac"}, {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:733ae23ada68b804b222c44affed76b39e30806d38660bf1eb200520d259cc16"},
{file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e"}, {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5fdfad2093bdd08245f2e204d977facd5f871c88c4a71230d5bcbd0e43bf6222"},
{file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f"}, {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cededd6738e1c153530793998e31c05086582b08315db48ab66649768f326baa"},
{file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18"}, {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:14f440c7268c8f8633d1b3d443a434bd70cb15686117ea6beff8fdc8f5917a1e"},
{file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a"}, {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3a2479753bbb95b0ebcf7969f562cdb9668e6d12416a35b0dda79febf89cdea2"},
{file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7"}, {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:71924496986275a737f38e3f22b4e0878882b3f7a310d2ff4dc96e812789120c"},
{file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401"}, {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4a9eefdc70bf8bf9857f0290f973dec534ac84c35cd6a7f4083be43e7170a8f"},
{file = "orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8"}, {file = "orjson-3.11.7-cp310-cp310-win32.whl", hash = "sha256:ae9e0b37a834cef7ce8f99de6498f8fad4a2c0bf6bfc3d02abd8ed56aa15b2de"},
{file = "orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167"}, {file = "orjson-3.11.7-cp310-cp310-win_amd64.whl", hash = "sha256:d772afdb22555f0c58cfc741bdae44180122b3616faa1ecadb595cd526e4c993"},
{file = "orjson-3.11.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9c8494625ad60a923af6b2b0bd74107146efe9b55099e20d7740d995f338fcd8"}, {file = "orjson-3.11.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9487abc2c2086e7c8eb9a211d2ce8855bae0e92586279d0d27b341d5ad76c85c"},
{file = "orjson-3.11.5-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:7bb2ce0b82bc9fd1168a513ddae7a857994b780b2945a8c51db4ab1c4b751ebc"}, {file = "orjson-3.11.7-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:79cacb0b52f6004caf92405a7e1f11e6e2de8bdf9019e4f76b44ba045125cd6b"},
{file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67394d3becd50b954c4ecd24ac90b5051ee7c903d167459f93e77fc6f5b4c968"}, {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e85fe4698b6a56d5e2ebf7ae87544d668eb6bde1ad1226c13f44663f20ec9e"},
{file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:298d2451f375e5f17b897794bcc3e7b821c0f32b4788b9bcae47ada24d7f3cf7"}, {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8d14b71c0b12963fe8a62aac87119f1afdf4cb88a400f61ca5ae581449efcb5"},
{file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa5e4244063db8e1d87e0f54c3f7522f14b2dc937e65d5241ef0076a096409fd"}, {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91c81ef070c8f3220054115e1ef468b1c9ce8497b4e526cb9f68ab4dc0a7ac62"},
{file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db2088b490761976c1b2e956d5d4e6409f3732e9d79cfa69f876c5248d1baf9"}, {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411ebaf34d735e25e358a6d9e7978954a9c9d58cfb47bc6683cdc3964cd2f910"},
{file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2ed66358f32c24e10ceea518e16eb3549e34f33a9d51f99ce23b0251776a1ef"}, {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a16bcd08ab0bcdfc7e8801d9c4a9cc17e58418e4d48ddc6ded4e9e4b1a94062b"},
{file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2021afda46c1ed64d74b555065dbd4c2558d510d8cec5ea6a53001b3e5e82a9"}, {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c0b51672e466fd7e56230ffbae7f1639e18d0ce023351fb75da21b71bc2c960"},
{file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b42ffbed9128e547a1647a3e50bc88ab28ae9daa61713962e0d3dd35e820c125"}, {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:136dcd6a2e796dfd9ffca9fc027d778567b0b7c9968d092842d3c323cef88aa8"},
{file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8d5f16195bb671a5dd3d1dbea758918bada8f6cc27de72bd64adfbd748770814"}, {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:7ba61079379b0ae29e117db13bda5f28d939766e410d321ec1624afc6a0b0504"},
{file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c0e5d9f7a0227df2927d343a6e3859bebf9208b427c79bd31949abcc2fa32fa5"}, {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0527a4510c300e3b406591b0ba69b5dc50031895b0a93743526a3fc45f59d26e"},
{file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23d04c4543e78f724c4dfe656b3791b5f98e4c9253e13b2636f1af5d90e4a880"}, {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a709e881723c9b18acddcfb8ba357322491ad553e277cf467e1e7e20e2d90561"},
{file = "orjson-3.11.5-cp311-cp311-win32.whl", hash = "sha256:c404603df4865f8e0afe981aa3c4b62b406e6d06049564d58934860b62b7f91d"}, {file = "orjson-3.11.7-cp311-cp311-win32.whl", hash = "sha256:c43b8b5bab288b6b90dac410cca7e986a4fa747a2e8f94615aea407da706980d"},
{file = "orjson-3.11.5-cp311-cp311-win_amd64.whl", hash = "sha256:9645ef655735a74da4990c24ffbd6894828fbfa117bc97c1edd98c282ecb52e1"}, {file = "orjson-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:6543001328aa857187f905308a028935864aefe9968af3848401b6fe80dbb471"},
{file = "orjson-3.11.5-cp311-cp311-win_arm64.whl", hash = "sha256:1cbf2735722623fcdee8e712cbaaab9e372bbcb0c7924ad711b261c2eccf4a5c"}, {file = "orjson-3.11.7-cp311-cp311-win_arm64.whl", hash = "sha256:1ee5cc7160a821dfe14f130bc8e63e7611051f964b463d9e2a3a573204446a4d"},
{file = "orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d"}, {file = "orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f"},
{file = "orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626"}, {file = "orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b"},
{file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f"}, {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a"},
{file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85"}, {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10"},
{file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9"}, {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa"},
{file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626"}, {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8"},
{file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa"}, {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f"},
{file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477"}, {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad"},
{file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e"}, {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867"},
{file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69"}, {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d"},
{file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3"}, {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab"},
{file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca"}, {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2"},
{file = "orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98"}, {file = "orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f"},
{file = "orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875"}, {file = "orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74"},
{file = "orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe"}, {file = "orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5"},
{file = "orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629"}, {file = "orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733"},
{file = "orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3"}, {file = "orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4"},
{file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39"}, {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785"},
{file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f"}, {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539"},
{file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51"}, {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1"},
{file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8"}, {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1"},
{file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706"}, {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705"},
{file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f"}, {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace"},
{file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863"}, {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b"},
{file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228"}, {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157"},
{file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2"}, {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3"},
{file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05"}, {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223"},
{file = "orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef"}, {file = "orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3"},
{file = "orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583"}, {file = "orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757"},
{file = "orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287"}, {file = "orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539"},
{file = "orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0"}, {file = "orjson-3.11.7-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0"},
{file = "orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81"}, {file = "orjson-3.11.7-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0"},
{file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f"}, {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6"},
{file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e"}, {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf"},
{file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7"}, {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5"},
{file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb"}, {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892"},
{file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4"}, {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e"},
{file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad"}, {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1"},
{file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829"}, {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183"},
{file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac"}, {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650"},
{file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d"}, {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141"},
{file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439"}, {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2"},
{file = "orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499"}, {file = "orjson-3.11.7-cp314-cp314-win32.whl", hash = "sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576"},
{file = "orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310"}, {file = "orjson-3.11.7-cp314-cp314-win_amd64.whl", hash = "sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1"},
{file = "orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5"}, {file = "orjson-3.11.7-cp314-cp314-win_arm64.whl", hash = "sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d"},
{file = "orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1b280e2d2d284a6713b0cfec7b08918ebe57df23e3f76b27586197afca3cb1e9"}, {file = "orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49"},
{file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d8a112b274fae8c5f0f01954cb0480137072c271f3f4958127b010dfefaec"},
{file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0a2ae6f09ac7bd47d2d5a5305c1d9ed08ac057cda55bb0a49fa506f0d2da00"},
{file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0d87bd1896faac0d10b4f849016db81a63e4ec5df38757ffae84d45ab38aa71"},
{file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:801a821e8e6099b8c459ac7540b3c32dba6013437c57fdcaec205b169754f38c"},
{file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a0f6ac618c98c74b7fbc8c0172ba86f9e01dbf9f62aa0b1776c2231a7bffe5"},
{file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fea7339bdd22e6f1060c55ac31b6a755d86a5b2ad3657f2669ec243f8e3b2bdb"},
{file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4dad582bc93cef8f26513e12771e76385a7e6187fd713157e971c784112aad56"},
{file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:0522003e9f7fba91982e83a97fec0708f5a714c96c4209db7104e6b9d132f111"},
{file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7403851e430a478440ecc1258bcbacbfbd8175f9ac1e39031a7121dd0de05ff8"},
{file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5f691263425d3177977c8d1dd896cde7b98d93cbf390b2544a090675e83a6a0a"},
{file = "orjson-3.11.5-cp39-cp39-win32.whl", hash = "sha256:61026196a1c4b968e1b1e540563e277843082e9e97d78afa03eb89315af531f1"},
{file = "orjson-3.11.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b94b947ac08586af635ef922d69dc9bc63321527a3a04647f4986a73f4bd30"},
{file = "orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5"},
] ]
[[package]] [[package]]
@@ -1967,4 +1954,4 @@ uvloop = ["uvloop"]
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "^3.13" python-versions = "^3.13"
content-hash = "1c3f9847499f900a728f2df17077249d90dacd192efbefc46e9fac795605f0f8" content-hash = "29ff358d6c84aa16c66c55a870bfc31442d090ce218785aeb4a83e71b9e863af"

View File

@@ -18,7 +18,7 @@ aiosqlite = "^0.20.0"
websockets = "^12.0" websockets = "^12.0"
pydantic = "^2.7.0" pydantic = "^2.7.0"
pydantic-settings = "^2.2.1" pydantic-settings = "^2.2.1"
orjson = "^3.11.5" orjson = "^3.11.6"
python-dotenv = "^1.0.1" python-dotenv = "^1.0.1"
httpx = "^0.27.0" httpx = "^0.27.0"
uvloop = ">=0.22.0" uvloop = ">=0.22.0"

View File

@@ -14,6 +14,9 @@ from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta from datetime import datetime, timedelta
import json import json
import os
import sqlite3
from pathlib import Path
from eth_account import Account from eth_account import Account
from eth_utils import to_checksum_address, keccak from eth_utils import to_checksum_address, keccak
@@ -49,9 +52,27 @@ class GuardianContract:
Guardian contract implementation for agent wallet protection Guardian contract implementation for agent wallet protection
""" """
def __init__(self, agent_address: str, config: GuardianConfig): def __init__(self, agent_address: str, config: GuardianConfig, storage_path: str = None):
self.agent_address = to_checksum_address(agent_address) self.agent_address = to_checksum_address(agent_address)
self.config = config self.config = config
# CRITICAL SECURITY FIX: Use persistent storage instead of in-memory
if storage_path is None:
storage_path = os.path.join(os.path.expanduser("~"), ".aitbc", "guardian_contracts")
self.storage_dir = Path(storage_path)
self.storage_dir.mkdir(parents=True, exist_ok=True)
# Database file for this contract
self.db_path = self.storage_dir / f"guardian_{self.agent_address}.db"
# Initialize persistent storage
self._init_storage()
# Load state from storage
self._load_state()
# In-memory cache for performance (synced with storage)
self.spending_history: List[Dict] = [] self.spending_history: List[Dict] = []
self.pending_operations: Dict[str, Dict] = {} self.pending_operations: Dict[str, Dict] = {}
self.paused = False self.paused = False
@@ -61,6 +82,156 @@ class GuardianContract:
self.nonce = 0 self.nonce = 0
self.guardian_approvals: Dict[str, bool] = {} self.guardian_approvals: Dict[str, bool] = {}
# Load data from persistent storage
self._load_spending_history()
self._load_pending_operations()
def _init_storage(self):
"""Initialize SQLite database for persistent storage"""
with sqlite3.connect(self.db_path) as conn:
conn.execute('''
CREATE TABLE IF NOT EXISTS spending_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
operation_id TEXT UNIQUE,
agent_address TEXT,
to_address TEXT,
amount INTEGER,
data TEXT,
timestamp TEXT,
executed_at TEXT,
status TEXT,
nonce INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
conn.execute('''
CREATE TABLE IF NOT EXISTS pending_operations (
operation_id TEXT PRIMARY KEY,
agent_address TEXT,
operation_data TEXT,
status TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
conn.execute('''
CREATE TABLE IF NOT EXISTS contract_state (
agent_address TEXT PRIMARY KEY,
nonce INTEGER DEFAULT 0,
paused BOOLEAN DEFAULT 0,
emergency_mode BOOLEAN DEFAULT 0,
last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
def _load_state(self):
"""Load contract state from persistent storage"""
with sqlite3.connect(self.db_path) as conn:
cursor = conn.execute(
'SELECT nonce, paused, emergency_mode FROM contract_state WHERE agent_address = ?',
(self.agent_address,)
)
row = cursor.fetchone()
if row:
self.nonce, self.paused, self.emergency_mode = row
else:
# Initialize state for new contract
conn.execute(
'INSERT INTO contract_state (agent_address, nonce, paused, emergency_mode) VALUES (?, ?, ?, ?)',
(self.agent_address, 0, False, False)
)
conn.commit()
def _save_state(self):
"""Save contract state to persistent storage"""
with sqlite3.connect(self.db_path) as conn:
conn.execute(
'UPDATE contract_state SET nonce = ?, paused = ?, emergency_mode = ?, last_updated = CURRENT_TIMESTAMP WHERE agent_address = ?',
(self.nonce, self.paused, self.emergency_mode, self.agent_address)
)
conn.commit()
def _load_spending_history(self):
"""Load spending history from persistent storage"""
with sqlite3.connect(self.db_path) as conn:
cursor = conn.execute(
'SELECT operation_id, to_address, amount, data, timestamp, executed_at, status, nonce FROM spending_history WHERE agent_address = ? ORDER BY timestamp DESC',
(self.agent_address,)
)
self.spending_history = []
for row in cursor:
self.spending_history.append({
"operation_id": row[0],
"to": row[1],
"amount": row[2],
"data": row[3],
"timestamp": row[4],
"executed_at": row[5],
"status": row[6],
"nonce": row[7]
})
def _save_spending_record(self, record: Dict):
"""Save spending record to persistent storage"""
with sqlite3.connect(self.db_path) as conn:
conn.execute(
'''INSERT OR REPLACE INTO spending_history
(operation_id, agent_address, to_address, amount, data, timestamp, executed_at, status, nonce)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)''',
(
record["operation_id"],
self.agent_address,
record["to"],
record["amount"],
record.get("data", ""),
record["timestamp"],
record.get("executed_at", ""),
record["status"],
record["nonce"]
)
)
conn.commit()
def _load_pending_operations(self):
"""Load pending operations from persistent storage"""
with sqlite3.connect(self.db_path) as conn:
cursor = conn.execute(
'SELECT operation_id, operation_data, status FROM pending_operations WHERE agent_address = ?',
(self.agent_address,)
)
self.pending_operations = {}
for row in cursor:
operation_data = json.loads(row[1])
operation_data["status"] = row[2]
self.pending_operations[row[0]] = operation_data
def _save_pending_operation(self, operation_id: str, operation: Dict):
"""Save pending operation to persistent storage"""
with sqlite3.connect(self.db_path) as conn:
conn.execute(
'''INSERT OR REPLACE INTO pending_operations
(operation_id, agent_address, operation_data, status, updated_at)
VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)''',
(operation_id, self.agent_address, json.dumps(operation), operation["status"])
)
conn.commit()
def _remove_pending_operation(self, operation_id: str):
"""Remove pending operation from persistent storage"""
with sqlite3.connect(self.db_path) as conn:
conn.execute(
'DELETE FROM pending_operations WHERE operation_id = ? AND agent_address = ?',
(operation_id, self.agent_address)
)
conn.commit()
def _get_period_key(self, timestamp: datetime, period: str) -> str: def _get_period_key(self, timestamp: datetime, period: str) -> str:
"""Generate period key for spending tracking""" """Generate period key for spending tracking"""
if period == "hour": if period == "hour":
@@ -266,11 +437,16 @@ class GuardianContract:
"nonce": operation["nonce"] "nonce": operation["nonce"]
} }
# CRITICAL SECURITY FIX: Save to persistent storage
self._save_spending_record(record)
self.spending_history.append(record) self.spending_history.append(record)
self.nonce += 1 self.nonce += 1
self._save_state()
# Remove from pending # Remove from pending storage
del self.pending_operations[operation_id] self._remove_pending_operation(operation_id)
if operation_id in self.pending_operations:
del self.pending_operations[operation_id]
return { return {
"status": "executed", "status": "executed",
@@ -298,6 +474,9 @@ class GuardianContract:
self.paused = True self.paused = True
self.emergency_mode = True self.emergency_mode = True
# CRITICAL SECURITY FIX: Save state to persistent storage
self._save_state()
return { return {
"status": "paused", "status": "paused",
"paused_at": datetime.utcnow().isoformat(), "paused_at": datetime.utcnow().isoformat(),
@@ -329,6 +508,9 @@ class GuardianContract:
self.paused = False self.paused = False
self.emergency_mode = False self.emergency_mode = False
# CRITICAL SECURITY FIX: Save state to persistent storage
self._save_state()
return { return {
"status": "unpaused", "status": "unpaused",
"unpaused_at": datetime.utcnow().isoformat(), "unpaused_at": datetime.utcnow().isoformat(),
@@ -417,14 +599,37 @@ def create_guardian_contract(
per_week: Maximum amount per week per_week: Maximum amount per week
time_lock_threshold: Amount that triggers time lock time_lock_threshold: Amount that triggers time lock
time_lock_delay: Time lock delay in hours time_lock_delay: Time lock delay in hours
guardians: List of guardian addresses guardians: List of guardian addresses (REQUIRED for security)
Returns: Returns:
Configured GuardianContract instance Configured GuardianContract instance
Raises:
ValueError: If no guardians are provided or guardians list is insufficient
""" """
if guardians is None: # CRITICAL SECURITY FIX: Require proper guardians, never default to agent address
# Default to using the agent address as guardian (should be overridden) if guardians is None or not guardians:
guardians = [agent_address] raise ValueError(
"❌ CRITICAL: Guardians are required for security. "
"Provide at least 3 trusted guardian addresses different from the agent address."
)
# Validate that guardians are different from agent address
agent_checksum = to_checksum_address(agent_address)
guardian_checksums = [to_checksum_address(g) for g in guardians]
if agent_checksum in guardian_checksums:
raise ValueError(
"❌ CRITICAL: Agent address cannot be used as guardian. "
"Guardians must be independent trusted addresses."
)
# Require minimum number of guardians for security
if len(guardian_checksums) < 3:
raise ValueError(
f"❌ CRITICAL: At least 3 guardians required for security, got {len(guardian_checksums)}. "
"Consider using a multi-sig wallet or trusted service providers."
)
limits = SpendingLimit( limits = SpendingLimit(
per_transaction=per_transaction, per_transaction=per_transaction,

View File

@@ -63,3 +63,13 @@ async def list_receipts(
offset: int = Query(default=0, ge=0), offset: int = Query(default=0, ge=0),
) -> ReceiptListResponse: ) -> ReceiptListResponse:
return _service(session).list_receipts(job_id=job_id, limit=limit, offset=offset) return _service(session).list_receipts(job_id=job_id, limit=limit, offset=offset)
@router.get("/transactions/{tx_hash}", summary="Get transaction details by hash")
async def get_transaction(
*,
session: Annotated[Session, Depends(get_session)],
tx_hash: str,
) -> dict:
"""Get transaction details by hash from blockchain RPC"""
return _service(session).get_transaction(tx_hash)

View File

@@ -262,3 +262,30 @@ class ExplorerService:
resolved_job_id = job_id or "all" resolved_job_id = job_id or "all"
return ReceiptListResponse(jobId=resolved_job_id, items=items) return ReceiptListResponse(jobId=resolved_job_id, items=items)
def get_transaction(self, tx_hash: str) -> dict:
"""Get transaction details by hash from blockchain RPC"""
rpc_base = settings.blockchain_rpc_url.rstrip("/")
try:
with httpx.Client(timeout=10.0) as client:
resp = client.get(f"{rpc_base}/rpc/tx/{tx_hash}")
if resp.status_code == 404:
return {"error": "Transaction not found", "hash": tx_hash}
resp.raise_for_status()
tx_data = resp.json()
# Map RPC schema to UI-compatible format
return {
"hash": tx_data.get("tx_hash", tx_hash),
"from": tx_data.get("sender", "unknown"),
"to": tx_data.get("recipient", "unknown"),
"amount": tx_data.get("payload", {}).get("value", "0"),
"fee": "0", # RPC doesn't provide fee info
"timestamp": tx_data.get("created_at"),
"block": tx_data.get("block_height", "pending"),
"status": "confirmed",
"raw": tx_data # Include raw data for debugging
}
except Exception as e:
print(f"Warning: Failed to fetch transaction {tx_hash} from RPC: {e}")
return {"error": f"Failed to fetch transaction: {str(e)}", "hash": tx_hash}

View File

@@ -48,11 +48,34 @@ class WalletService:
if existing: if existing:
raise ValueError(f"Agent {request.agent_id} already has an active {request.wallet_type} wallet") raise ValueError(f"Agent {request.agent_id} already has an active {request.wallet_type} wallet")
# Simulate key generation (in reality, use a secure KMS or HSM) # CRITICAL SECURITY FIX: Use proper secp256k1 key generation instead of fake SHA-256
priv_key = secrets.token_hex(32) try:
pub_key = hashlib.sha256(priv_key.encode()).hexdigest() from eth_account import Account
# Fake Ethereum address derivation for simulation from cryptography.fernet import Fernet
address = "0x" + hashlib.sha3_256(pub_key.encode()).hexdigest()[-40:] import base64
import secrets
# Generate proper secp256k1 key pair
account = Account.create()
priv_key = account.key.hex() # Proper 32-byte private key
pub_key = account.address # Ethereum address (derived from public key)
address = account.address # Same as pub_key for Ethereum
# Encrypt private key securely (in production, use KMS/HSM)
encryption_key = Fernet.generate_key()
f = Fernet(encryption_key)
encrypted_private_key = f.encrypt(priv_key.encode()).decode()
except ImportError:
# Fallback for development (still more secure than SHA-256)
logger.error("❌ CRITICAL: eth-account not available. Using fallback key generation.")
import os
priv_key = secrets.token_hex(32)
# Generate a proper address using keccak256 (still not ideal but better than SHA-256)
from eth_utils import keccak
pub_key = keccak(bytes.fromhex(priv_key))
address = "0x" + pub_key[-20:].hex()
encrypted_private_key = "[ENCRYPTED_MOCK_FALLBACK]"
wallet = AgentWallet( wallet = AgentWallet(
agent_id=request.agent_id, agent_id=request.agent_id,
@@ -60,7 +83,7 @@ class WalletService:
public_key=pub_key, public_key=pub_key,
wallet_type=request.wallet_type, wallet_type=request.wallet_type,
metadata=request.metadata, metadata=request.metadata,
encrypted_private_key="[ENCRYPTED_MOCK]" # Real implementation would encrypt it securely encrypted_private_key=encrypted_private_key # CRITICAL: Use proper encryption
) )
self.session.add(wallet) self.session.add(wallet)

View File

@@ -0,0 +1,216 @@
#!/usr/bin/env python3
"""
Simple AITBC Blockchain Explorer - Demonstrating the issues described in the analysis
"""
import asyncio
import httpx
from datetime import datetime
from typing import Dict, Any, Optional
from fastapi import FastAPI, HTTPException
from fastapi.responses import HTMLResponse
import uvicorn
app = FastAPI(title="Simple AITBC Explorer", version="0.1.0")
# Configuration
BLOCKCHAIN_RPC_URL = "http://localhost:8025"
# HTML Template with the problematic frontend
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple AITBC Explorer</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-50">
<div class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold mb-8">AITBC Blockchain Explorer</h1>
<!-- Search -->
<div class="bg-white rounded-lg shadow p-6 mb-8">
<h2 class="text-xl font-semibold mb-4">Search</h2>
<div class="flex space-x-4">
<input type="text" id="search-input" placeholder="Search by transaction hash (64 chars)"
class="flex-1 px-4 py-2 border rounded-lg">
<button onclick="performSearch()" class="bg-blue-600 text-white px-6 py-2 rounded-lg">
Search
</button>
</div>
</div>
<!-- Results -->
<div id="results" class="hidden bg-white rounded-lg shadow p-6">
<h2 class="text-xl font-semibold mb-4">Transaction Details</h2>
<div id="tx-details"></div>
</div>
<!-- Latest Blocks -->
<div class="bg-white rounded-lg shadow p-6">
<h2 class="text-xl font-semibold mb-4">Latest Blocks</h2>
<div id="blocks-list"></div>
</div>
</div>
<script>
// Problem 1: Frontend calls /api/transactions/{hash} but backend doesn't have it
async function performSearch() {
const query = document.getElementById('search-input').value.trim();
if (!query) return;
if (/^[a-fA-F0-9]{64}$/.test(query)) {
try {
const tx = await fetch(`/api/transactions/${query}`).then(r => {
if (!r.ok) throw new Error('Transaction not found');
return r.json();
});
showTransactionDetails(tx);
} catch (error) {
alert('Transaction not found');
}
} else {
alert('Please enter a valid 64-character hex transaction hash');
}
}
// Problem 2: UI expects tx.hash, tx.from, tx.to, tx.amount, tx.fee
// But RPC returns tx_hash, sender, recipient, payload, created_at
function showTransactionDetails(tx) {
const resultsDiv = document.getElementById('results');
const detailsDiv = document.getElementById('tx-details');
detailsDiv.innerHTML = `
<div class="space-y-4">
<div><strong>Hash:</strong> ${tx.hash || 'N/A'}</div>
<div><strong>From:</strong> ${tx.from || 'N/A'}</div>
<div><strong>To:</strong> ${tx.to || 'N/A'}</div>
<div><strong>Amount:</strong> ${tx.amount || 'N/A'}</div>
<div><strong>Fee:</strong> ${tx.fee || 'N/A'}</div>
<div><strong>Timestamp:</strong> ${formatTimestamp(tx.timestamp)}</div>
</div>
`;
resultsDiv.classList.remove('hidden');
}
// Problem 3: formatTimestamp now handles both numeric and ISO string timestamps
function formatTimestamp(timestamp) {
if (!timestamp) return 'N/A';
// Handle ISO string timestamps
if (typeof timestamp === 'string') {
try {
return new Date(timestamp).toLocaleString();
} catch (e) {
return 'Invalid timestamp';
}
}
// Handle numeric timestamps (Unix seconds)
if (typeof timestamp === 'number') {
try {
return new Date(timestamp * 1000).toLocaleString();
} catch (e) {
return 'Invalid timestamp';
}
}
return 'Invalid timestamp format';
}
// Load latest blocks
async function loadBlocks() {
try {
const head = await fetch('/api/chain/head').then(r => r.json());
const blocksList = document.getElementById('blocks-list');
let html = '<div class="space-y-4">';
for (let i = 0; i < 5 && head.height - i >= 0; i++) {
const block = await fetch(`/api/blocks/${head.height - i}`).then(r => r.json());
html += `
<div class="border rounded p-4">
<div><strong>Height:</strong> ${block.height}</div>
<div><strong>Hash:</strong> ${block.hash ? block.hash.substring(0, 16) + '...' : 'N/A'}</div>
<div><strong>Time:</strong> ${formatTimestamp(block.timestamp)}</div>
</div>
`;
}
html += '</div>';
blocksList.innerHTML = html;
} catch (error) {
console.error('Failed to load blocks:', error);
}
}
// Initialize
document.addEventListener('DOMContentLoaded', () => {
loadBlocks();
});
</script>
</body>
</html>
"""
# Problem 1: Only /api/chain/head and /api/blocks/{height} defined, missing /api/transactions/{hash}
@app.get("/api/chain/head")
async def get_chain_head():
"""Get current chain head"""
try:
async with httpx.AsyncClient() as client:
response = await client.get(f"{BLOCKCHAIN_RPC_URL}/rpc/head")
if response.status_code == 200:
return response.json()
except Exception as e:
print(f"Error getting chain head: {e}")
return {"height": 0, "hash": "", "timestamp": None}
@app.get("/api/blocks/{height}")
async def get_block(height: int):
"""Get block by height"""
try:
async with httpx.AsyncClient() as client:
response = await client.get(f"{BLOCKCHAIN_RPC_URL}/rpc/blocks/{height}")
if response.status_code == 200:
return response.json()
except Exception as e:
print(f"Error getting block {height}: {e}")
return {"height": height, "hash": "", "timestamp": None, "transactions": []}
@app.get("/api/transactions/{tx_hash}")
async def get_transaction(tx_hash: str):
"""Get transaction by hash - Problem 1: This endpoint was missing"""
try:
async with httpx.AsyncClient() as client:
response = await client.get(f"{BLOCKCHAIN_RPC_URL}/rpc/tx/{tx_hash}")
if response.status_code == 200:
tx_data = response.json()
# Problem 2: Map RPC schema to UI schema
return {
"hash": tx_data.get("tx_hash", tx_hash), # tx_hash -> hash
"from": tx_data.get("sender", "unknown"), # sender -> from
"to": tx_data.get("recipient", "unknown"), # recipient -> to
"amount": tx_data.get("payload", {}).get("value", "0"), # payload.value -> amount
"fee": tx_data.get("payload", {}).get("fee", "0"), # payload.fee -> fee
"timestamp": tx_data.get("created_at"), # created_at -> timestamp
"block_height": tx_data.get("block_height", "pending")
}
elif response.status_code == 404:
raise HTTPException(status_code=404, detail="Transaction not found")
except HTTPException:
raise
except Exception as e:
print(f"Error getting transaction {tx_hash}: {e}")
raise HTTPException(status_code=500, detail=f"Failed to fetch transaction: {str(e)}")
# Missing: @app.get("/api/transactions/{tx_hash}") - THIS IS THE PROBLEM
@app.get("/", response_class=HTMLResponse)
async def root():
"""Serve the explorer UI"""
return HTML_TEMPLATE
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8017)

View File

@@ -0,0 +1,316 @@
#!/usr/bin/env python3
"""
OpenClaw DAO CLI Commands
Provides command-line interface for DAO governance operations
"""
import click
import json
from datetime import datetime, timedelta
from typing import List, Dict, Any
from web3 import Web3
from ..utils.blockchain import get_web3_connection, get_contract
from ..utils.config import load_config
@click.group()
def dao():
"""OpenClaw DAO governance commands"""
pass
@dao.command()
@click.option('--token-address', required=True, help='Governance token contract address')
@click.option('--timelock-address', required=True, help='Timelock controller address')
@click.option('--network', default='mainnet', help='Blockchain network')
def deploy(token_address: str, timelock_address: str, network: str):
"""Deploy OpenClaw DAO contract"""
try:
w3 = get_web3_connection(network)
config = load_config()
# Account for deployment
account = w3.eth.account.from_key(config['private_key'])
# Contract ABI (simplified)
abi = [
{
"inputs": [
{"internalType": "address", "name": "_governanceToken", "type": "address"},
{"internalType": "contract TimelockController", "name": "_timelock", "type": "address"}
],
"stateMutability": "nonpayable",
"type": "constructor"
}
]
# Deploy contract
contract = w3.eth.contract(abi=abi, bytecode="0x...") # Actual bytecode needed
# Build transaction
tx = contract.constructor(token_address, timelock_address).build_transaction({
'from': account.address,
'gas': 2000000,
'gasPrice': w3.eth.gas_price,
'nonce': w3.eth.get_transaction_count(account.address)
})
# Sign and send
signed_tx = w3.eth.account.sign_transaction(tx, config['private_key'])
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
# Wait for confirmation
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
click.echo(f"✅ OpenClaw DAO deployed at: {receipt.contractAddress}")
click.echo(f"📦 Transaction hash: {tx_hash.hex()}")
except Exception as e:
click.echo(f"❌ Deployment failed: {str(e)}", err=True)
@dao.command()
@click.option('--dao-address', required=True, help='DAO contract address')
@click.option('--targets', required=True, help='Comma-separated target addresses')
@click.option('--values', required=True, help='Comma-separated ETH values')
@click.option('--calldatas', required=True, help='Comma-separated hex calldatas')
@click.option('--description', required=True, help='Proposal description')
@click.option('--type', 'proposal_type', type=click.Choice(['0', '1', '2', '3']),
default='0', help='Proposal type (0=parameter, 1=upgrade, 2=treasury, 3=emergency)')
def propose(dao_address: str, targets: str, values: str, calldatas: str,
description: str, proposal_type: str):
"""Create a new governance proposal"""
try:
w3 = get_web3_connection()
config = load_config()
# Parse inputs
target_addresses = targets.split(',')
value_list = [int(v) for v in values.split(',')]
calldata_list = calldatas.split(',')
# Get contract
dao_contract = get_contract(dao_address, "OpenClawDAO")
# Build transaction
tx = dao_contract.functions.propose(
target_addresses,
value_list,
calldata_list,
description,
int(proposal_type)
).build_transaction({
'from': config['address'],
'gas': 500000,
'gasPrice': w3.eth.gas_price,
'nonce': w3.eth.get_transaction_count(config['address'])
})
# Sign and send
signed_tx = w3.eth.account.sign_transaction(tx, config['private_key'])
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
# Get proposal ID
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
# Parse proposal ID from events
proposal_id = None
for log in receipt.logs:
try:
event = dao_contract.events.ProposalCreated().process_log(log)
proposal_id = event.args.proposalId
break
except:
continue
click.echo(f"✅ Proposal created!")
click.echo(f"📋 Proposal ID: {proposal_id}")
click.echo(f"📦 Transaction hash: {tx_hash.hex()}")
except Exception as e:
click.echo(f"❌ Proposal creation failed: {str(e)}", err=True)
@dao.command()
@click.option('--dao-address', required=True, help='DAO contract address')
@click.option('--proposal-id', required=True, type=int, help='Proposal ID')
def vote(dao_address: str, proposal_id: int):
"""Cast a vote on a proposal"""
try:
w3 = get_web3_connection()
config = load_config()
# Get contract
dao_contract = get_contract(dao_address, "OpenClawDAO")
# Check proposal state
state = dao_contract.functions.state(proposal_id).call()
if state != 1: # Active
click.echo("❌ Proposal is not active for voting")
return
# Get voting power
token_address = dao_contract.functions.governanceToken().call()
token_contract = get_contract(token_address, "ERC20")
voting_power = token_contract.functions.balanceOf(config['address']).call()
if voting_power == 0:
click.echo("❌ No voting power (no governance tokens)")
return
click.echo(f"🗳️ Your voting power: {voting_power}")
# Get vote choice
support = click.prompt(
"Vote (0=Against, 1=For, 2=Abstain)",
type=click.Choice(['0', '1', '2'])
)
reason = click.prompt("Reason (optional)", default="", show_default=False)
# Build transaction
tx = dao_contract.functions.castVoteWithReason(
proposal_id,
int(support),
reason
).build_transaction({
'from': config['address'],
'gas': 100000,
'gasPrice': w3.eth.gas_price,
'nonce': w3.eth.get_transaction_count(config['address'])
})
# Sign and send
signed_tx = w3.eth.account.sign_transaction(tx, config['private_key'])
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
click.echo(f"✅ Vote cast!")
click.echo(f"📦 Transaction hash: {tx_hash.hex()}")
except Exception as e:
click.echo(f"❌ Voting failed: {str(e)}", err=True)
@dao.command()
@click.option('--dao-address', required=True, help='DAO contract address')
@click.option('--proposal-id', required=True, type=int, help='Proposal ID')
def execute(dao_address: str, proposal_id: int):
"""Execute a successful proposal"""
try:
w3 = get_web3_connection()
config = load_config()
# Get contract
dao_contract = get_contract(dao_address, "OpenClawDAO")
# Check proposal state
state = dao_contract.functions.state(proposal_id).call()
if state != 7: # Succeeded
click.echo("❌ Proposal has not succeeded")
return
# Build transaction
tx = dao_contract.functions.execute(proposal_id).build_transaction({
'from': config['address'],
'gas': 300000,
'gasPrice': w3.eth.gas_price,
'nonce': w3.eth.get_transaction_count(config['address'])
})
# Sign and send
signed_tx = w3.eth.account.sign_transaction(tx, config['private_key'])
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
click.echo(f"✅ Proposal executed!")
click.echo(f"📦 Transaction hash: {tx_hash.hex()}")
except Exception as e:
click.echo(f"❌ Execution failed: {str(e)}", err=True)
@dao.command()
@click.option('--dao-address', required=True, help='DAO contract address')
def list_proposals(dao_address: str):
"""List all proposals"""
try:
w3 = get_web3_connection()
dao_contract = get_contract(dao_address, "OpenClawDAO")
# Get proposal count
proposal_count = dao_contract.functions.proposalCount().call()
click.echo(f"📋 Found {proposal_count} proposals:\n")
for i in range(1, proposal_count + 1):
try:
proposal = dao_contract.functions.getProposal(i).call()
state = dao_contract.functions.state(i).call()
state_names = {
0: "Pending",
1: "Active",
2: "Canceled",
3: "Defeated",
4: "Succeeded",
5: "Queued",
6: "Expired",
7: "Executed"
}
type_names = {
0: "Parameter Change",
1: "Protocol Upgrade",
2: "Treasury Allocation",
3: "Emergency Action"
}
click.echo(f"🔹 Proposal #{i}")
click.echo(f" Type: {type_names.get(proposal[3], 'Unknown')}")
click.echo(f" State: {state_names.get(state, 'Unknown')}")
click.echo(f" Description: {proposal[4]}")
click.echo(f" For: {proposal[6]}, Against: {proposal[7]}, Abstain: {proposal[8]}")
click.echo()
except Exception as e:
continue
except Exception as e:
click.echo(f"❌ Failed to list proposals: {str(e)}", err=True)
@dao.command()
@click.option('--dao-address', required=True, help='DAO contract address')
def status(dao_address: str):
"""Show DAO status and statistics"""
try:
w3 = get_web3_connection()
dao_contract = get_contract(dao_address, "OpenClawDAO")
# Get DAO info
token_address = dao_contract.functions.governanceToken().call()
token_contract = get_contract(token_address, "ERC20")
total_supply = token_contract.functions.totalSupply().call()
proposal_count = dao_contract.functions.proposalCount().call()
# Get active proposals
active_proposals = dao_contract.functions.getActiveProposals().call()
click.echo("🏛️ OpenClaw DAO Status")
click.echo("=" * 40)
click.echo(f"📊 Total Supply: {total_supply / 1e18:.2f} tokens")
click.echo(f"📋 Total Proposals: {proposal_count}")
click.echo(f"🗳️ Active Proposals: {len(active_proposals)}")
click.echo(f"🪙 Governance Token: {token_address}")
click.echo(f"🏛️ DAO Address: {dao_address}")
# Voting parameters
voting_delay = dao_contract.functions.votingDelay().call()
voting_period = dao_contract.functions.votingPeriod().call()
quorum = dao_contract.functions.quorum(w3.eth.block_number).call()
threshold = dao_contract.functions.proposalThreshold().call()
click.echo(f"\n⚙️ Voting Parameters:")
click.echo(f" Delay: {voting_delay // 86400} days")
click.echo(f" Period: {voting_period // 86400} days")
click.echo(f" Quorum: {quorum / 1e18:.2f} tokens ({(quorum * 100 / total_supply):.2f}%)")
click.echo(f" Threshold: {threshold / 1e18:.2f} tokens")
except Exception as e:
click.echo(f"❌ Failed to get status: {str(e)}", err=True)
if __name__ == '__main__':
dao()

View File

@@ -1233,11 +1233,18 @@ def unstake(ctx, amount: float):
} }
) )
# Save wallet with encryption # CRITICAL SECURITY FIX: Save wallet properly to avoid double-encryption
password = None
if wallet_data.get("encrypted"): if wallet_data.get("encrypted"):
# For encrypted wallets, we need to re-encrypt the private key before saving
password = _get_wallet_password(wallet_name) password = _get_wallet_password(wallet_name)
_save_wallet(wallet_path, wallet_data, password) # Only encrypt the private key, not the entire wallet data
if "private_key" in wallet_data:
wallet_data["private_key"] = encrypt_value(wallet_data["private_key"], password)
# Save without passing password to avoid double-encryption
_save_wallet(wallet_path, wallet_data, None)
else:
# For unencrypted wallets, save normally
_save_wallet(wallet_path, wallet_data, None)
success(f"Unstaked {amount} AITBC") success(f"Unstaked {amount} AITBC")
output( output(

View File

@@ -364,8 +364,11 @@ class DualModeWalletAdapter:
wallet_data["transactions"].append(transaction) wallet_data["transactions"].append(transaction)
wallet_data["balance"] = chain_balance - amount wallet_data["balance"] = chain_balance - amount
# Save wallet # Save wallet - CRITICAL SECURITY FIX: Always use password if wallet is encrypted
save_password = password if wallet_data.get("encrypted") else None save_password = password if wallet_data.get("encrypted") else None
if wallet_data.get("encrypted") and not save_password:
error("❌ CRITICAL: Cannot save encrypted wallet without password")
raise Exception("Password required for encrypted wallet")
_save_wallet(wallet_path, wallet_data, save_password) _save_wallet(wallet_path, wallet_data, save_password)
success(f"Submitted transaction {tx_hash} to send {amount} AITBC to {to_address}") success(f"Submitted transaction {tx_hash} to send {amount} AITBC to {to_address}")

View File

@@ -70,17 +70,74 @@ class AuditLogger:
def _get_fernet_key(key: str = None) -> bytes: def _get_fernet_key(key: str = None) -> bytes:
"""Derive a Fernet key from a password or use default""" """Derive a Fernet key from a password using Argon2 KDF"""
from cryptography.fernet import Fernet from cryptography.fernet import Fernet
import base64 import base64
import hashlib import secrets
import getpass
if key is None: if key is None:
# Use a default key (should be overridden in production) # CRITICAL SECURITY FIX: Never use hardcoded keys
key = "aitbc_config_key_2026_default" # Always require user to provide a password or generate a secure random key
error("❌ CRITICAL: No encryption key provided. This is a security vulnerability.")
error("Please provide a password for encryption.")
key = getpass.getpass("Enter encryption password: ")
if not key:
error("❌ Password cannot be empty for encryption operations.")
raise ValueError("Encryption password is required")
# Derive a 32-byte key suitable for Fernet # Use Argon2 for secure key derivation (replaces insecure SHA-256)
return base64.urlsafe_b64encode(hashlib.sha256(key.encode()).digest()) try:
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
# Generate a secure salt
salt = secrets.token_bytes(16)
# Derive key using Argon2
ph = PasswordHasher(
time_cost=3, # Number of iterations
memory_cost=65536, # Memory usage in KB
parallelism=4, # Number of parallel threads
hash_len=32, # Output hash length
salt_len=16 # Salt length
)
# Hash the password to get a 32-byte key
hashed_key = ph.hash(key + salt.decode('utf-8'))
# Extract the hash part and convert to bytes suitable for Fernet
key_bytes = hashed_key.encode('utf-8')[:32]
# Ensure we have exactly 32 bytes for Fernet
if len(key_bytes) < 32:
key_bytes += secrets.token_bytes(32 - len(key_bytes))
elif len(key_bytes) > 32:
key_bytes = key_bytes[:32]
return base64.urlsafe_b64encode(key_bytes)
except ImportError:
# Fallback to PBKDF2 if Argon2 is not available
import hashlib
import hmac
warning("⚠️ Argon2 not available, falling back to PBKDF2 (less secure)")
# Generate a secure salt
salt = secrets.token_bytes(16)
# Use PBKDF2 with SHA-256 (better than plain SHA-256)
key_bytes = hashlib.pbkdf2_hmac(
'sha256',
key.encode('utf-8'),
salt,
100000, # 100k iterations
32 # 32-byte key
)
return base64.urlsafe_b64encode(key_bytes)
def encrypt_value(value: str, key: str = None) -> str: def encrypt_value(value: str, key: str = None) -> str:

View File

@@ -0,0 +1,346 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./OpenClawDAO.sol";
/**
* @title AgentWallet
* @dev Smart contract wallet for AI agents to participate in OpenClaw DAO governance
* @notice Enables autonomous voting and reputation-based governance participation
*/
contract AgentWallet is Ownable {
using SafeMath for uint256;
// Agent roles matching OpenClawDAO
enum AgentRole {
NONE,
PROVIDER,
CONSUMER,
BUILDER,
COORDINATOR
}
// Agent state
struct AgentState {
AgentRole role;
uint256 reputation;
uint256 lastVote;
uint256 votingPower;
bool isActive;
address daoContract;
mapping(uint256 => bool) votedProposals;
mapping(address => bool) authorizedCallers;
}
// Voting strategy configuration
struct VotingStrategy {
bool autoVote;
uint8 supportThreshold; // 0-255, higher means more likely to support
uint256 minReputationToVote;
bool voteBasedOnRole;
mapping(OpenClawDAO.ProposalType => uint8) roleVotingPreferences;
}
// State variables
AgentState public agentState;
VotingStrategy public votingStrategy;
OpenClawDAO public dao;
IERC20 public governanceToken;
// Events
event AgentRegistered(address indexed agent, AgentRole role, address dao);
event VoteCast(uint256 indexed proposalId, bool support, string reason);
event ReputationUpdated(uint256 oldReputation, uint256 newReputation);
event StrategyUpdated(bool autoVote, uint8 supportThreshold);
event AutonomousVoteExecuted(uint256 indexed proposalId, bool support);
// Modifiers
modifier onlyAuthorized() {
require(
msg.sender == owner() ||
agentState.authorizedCallers[msg.sender] ||
msg.sender == address(agentState.daoContract),
"Not authorized"
);
_;
}
modifier onlyActiveAgent() {
require(agentState.isActive, "Agent not active");
_;
}
constructor(
address _owner,
AgentRole _role,
address _daoContract,
address _governanceToken
) Ownable(_owner) {
agentState.role = _role;
agentState.daoContract = _daoContract;
agentState.isActive = true;
agentState.authorizedCallers[_owner] = true;
dao = OpenClawDAO(_daoContract);
governanceToken = IERC20(_governanceToken);
// Set default voting strategy based on role
_setDefaultVotingStrategy(_role);
emit AgentRegistered(_owner, _role, _daoContract);
}
/**
* @dev Register agent with OpenClaw DAO
*/
function registerWithDAO() external onlyAuthorized {
dao.registerAgentWallet(address(this), agentState.role);
}
/**
* @dev Cast vote on proposal
* @param proposalId ID of the proposal
* @param support Whether to support (true) or oppose (false)
* @param reason Voting reason
*/
function castVote(
uint256 proposalId,
bool support,
string calldata reason
) external onlyAuthorized onlyActiveAgent {
require(!agentState.votedProposals[proposalId], "Already voted");
// Check reputation requirement
require(
agentState.reputation >= votingStrategy.minReputationToVote,
"Insufficient reputation"
);
// Cast vote through DAO
uint8 supportValue = support ? 1 : 0;
dao.castVoteWithReason(proposalId, supportValue, reason);
// Update agent state
agentState.lastVote = block.timestamp;
agentState.votedProposals[proposalId] = true;
emit VoteCast(proposalId, support, reason);
}
/**
* @dev Autonomous voting based on strategy
* @param proposalId ID of the proposal
*/
function autonomousVote(uint256 proposalId) external onlyAuthorized onlyActiveAgent {
require(votingStrategy.autoVote, "Auto-vote disabled");
require(!agentState.votedProposals[proposalId], "Already voted");
// Get proposal details from DAO
(, , , , , , , , , ) = dao.getProposal(proposalId);
// Determine vote based on strategy
bool support = _calculateAutonomousVote(proposalId);
// Cast the vote
string memory reason = _generateVotingReason(proposalId, support);
castVote(proposalId, support, reason);
emit AutonomousVoteExecuted(proposalId, support);
}
/**
* @dev Update agent reputation
* @param newReputation New reputation score
*/
function updateReputation(uint256 newReputation) external onlyAuthorized {
uint256 oldReputation = agentState.reputation;
agentState.reputation = newReputation;
emit ReputationUpdated(oldReputation, newReputation);
}
/**
* @dev Update voting strategy
* @param autoVote Whether to enable autonomous voting
* @param supportThreshold Support threshold (0-255)
*/
function updateVotingStrategy(
bool autoVote,
uint8 supportThreshold
) external onlyAuthorized {
votingStrategy.autoVote = autoVote;
votingStrategy.supportThreshold = supportThreshold;
emit StrategyUpdated(autoVote, supportThreshold);
}
/**
* @dev Set role-specific voting preferences
* @param proposalType Proposal type
* @param preference Voting preference (0-255)
*/
function setRoleVotingPreference(
OpenClawDAO.ProposalType proposalType,
uint8 preference
) external onlyAuthorized {
votingStrategy.roleVotingPreferences[proposalType] = preference;
}
/**
* @dev Add authorized caller
* @param caller Address to authorize
*/
function addAuthorizedCaller(address caller) external onlyOwner {
agentState.authorizedCallers[caller] = true;
}
/**
* @dev Remove authorized caller
* @param caller Address to remove
*/
function removeAuthorizedCaller(address caller) external onlyOwner {
agentState.authorizedCallers[caller] = false;
}
/**
* @dev Get current voting power
* @return votingPower Current voting power
*/
function getVotingPower() external view returns (uint256) {
return governanceToken.balanceOf(address(this));
}
/**
* @dev Check if agent can vote on proposal
* @param proposalId ID of the proposal
* @return canVote Whether agent can vote
*/
function canVote(uint256 proposalId) external view returns (bool) {
if (!agentState.isActive) return false;
if (agentState.votedProposals[proposalId]) return false;
if (agentState.reputation < votingStrategy.minReputationToVote) return false;
return true;
}
/**
* @dev Calculate autonomous vote based on strategy
* @param proposalId ID of the proposal
* @return support Whether to support the proposal
*/
function _calculateAutonomousVote(uint256 proposalId) internal view returns (bool) {
// Get proposal type preference
(, , , OpenClawDAO.ProposalType proposalType, , , , , , ) = dao.getProposal(proposalId);
uint8 preference = votingStrategy.roleVotingPreferences[proposalType];
// Combine with general support threshold
uint256 combinedScore = uint256(preference) + uint256(votingStrategy.supportThreshold);
uint256 midpoint = 256; // Midpoint of 0-511 range
return combinedScore > midpoint;
}
/**
* @dev Generate voting reason based on strategy
* @param proposalId ID of the proposal
* @param support Whether supporting or opposing
* @return reason Generated voting reason
*/
function _generateVotingReason(
uint256 proposalId,
bool support
) internal view returns (string memory) {
(, , , OpenClawDAO.ProposalType proposalType, , , , , , ) = dao.getProposal(proposalId);
string memory roleString = _roleToString(agentState.role);
string memory actionString = support ? "support" : "oppose";
string memory typeString = _proposalTypeToString(proposalType);
return string(abi.encodePacked(
"Autonomous ",
roleString,
" agent votes to ",
actionString,
" ",
typeString,
" proposal based on strategy"
));
}
/**
* @dev Set default voting strategy based on role
* @param role Agent role
*/
function _setDefaultVotingStrategy(AgentRole role) internal {
votingStrategy.minReputationToVote = 100; // Default minimum reputation
if (role == AgentRole.PROVIDER) {
// Providers favor infrastructure and resource proposals
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.PARAMETER_CHANGE] = 180;
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.TREASURY_ALLOCATION] = 160;
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.AGENT_TRADING] = 200;
votingStrategy.supportThreshold = 128;
} else if (role == AgentRole.CONSUMER) {
// Consumers favor access and pricing proposals
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.PARAMETER_CHANGE] = 140;
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.TREASURY_ALLOCATION] = 180;
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.AGENT_TRADING] = 160;
votingStrategy.supportThreshold = 128;
} else if (role == AgentRole.BUILDER) {
// Builders favor development and upgrade proposals
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.PROTOCOL_UPGRADE] = 200;
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.DAO_GRANTS] = 180;
votingStrategy.supportThreshold = 150;
} else if (role == AgentRole.COORDINATOR) {
// Coordinators favor governance and system proposals
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.PARAMETER_CHANGE] = 160;
votingStrategy.roleVotingPreferences[OpenClawDAO.ProposalType.PROTOCOL_UPGRADE] = 180;
votingStrategy.supportThreshold = 140;
}
}
/**
* @dev Convert role enum to string
* @param role Agent role
* @return roleString String representation
*/
function _roleToString(AgentRole role) internal pure returns (string memory) {
if (role == AgentRole.PROVIDER) return "Provider";
if (role == AgentRole.CONSUMER) return "Consumer";
if (role == AgentRole.BUILDER) return "Builder";
if (role == AgentRole.COORDINATOR) return "Coordinator";
return "Unknown";
}
/**
* @dev Convert proposal type enum to string
* @param proposalType Proposal type
* @return typeString String representation
*/
function _proposalTypeToString(OpenClawDAO.ProposalType proposalType) internal pure returns (string memory) {
if (proposalType == OpenClawDAO.ProposalType.PARAMETER_CHANGE) return "Parameter Change";
if (proposalType == OpenClawDAO.ProposalType.PROTOCOL_UPGRADE) return "Protocol Upgrade";
if (proposalType == OpenClawDAO.ProposalType.TREASURY_ALLOCATION) return "Treasury Allocation";
if (proposalType == OpenClawDAO.ProposalType.EMERGENCY_ACTION) return "Emergency Action";
if (proposalType == OpenClawDAO.ProposalType.AGENT_TRADING) return "Agent Trading";
if (proposalType == OpenClawDAO.ProposalType.DAO_GRANTS) return "DAO Grants";
return "Unknown";
}
/**
* @dev Emergency stop - disable autonomous voting
*/
function emergencyStop() external onlyOwner {
votingStrategy.autoVote = false;
agentState.isActive = false;
}
/**
* @dev Reactivate agent
*/
function reactivate() external onlyOwner {
agentState.isActive = true;
}
}

View File

@@ -0,0 +1,449 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
/**
* @title GPUStaking
* @dev GPU resource staking and reward distribution for AITBC agents
* @notice Enables providers to stake GPU resources and earn rewards
*/
contract GPUStaking is Ownable, ReentrancyGuard {
using SafeMath for uint256;
// GPU resource structure
struct GPUResource {
address provider;
uint256 gpuPower; // Computational power units
uint256 lockPeriod; // Lock period in seconds
uint256 stakeAmount; // AITBC tokens staked
uint256 rewardRate; // Reward rate per second
uint256 reputation; // Provider reputation score
uint256 startTime; // When staking started
uint256 lastRewardTime; // Last reward calculation time
bool isActive; // Whether resource is active
string gpuSpecs; // GPU specifications (JSON)
}
// Staking pool structure
struct StakingPool {
uint256 totalGPUPower;
uint256 totalStaked;
uint256 rewardPool;
uint256 rewardRate;
uint256 utilizationRate; // Current utilization (0-10000 = 0-100%)
bool isActive;
mapping(address => uint256) providerContributions;
}
// Reward calculation structure
struct RewardInfo {
uint256 totalRewards;
uint256 pendingRewards;
uint256 lastClaimTime;
uint256 rewardHistory;
}
// State variables
IERC20 public stakingToken;
mapping(address => GPUResource) public gpuResources;
mapping(uint256 => StakingPool) public stakingPools;
mapping(address => RewardInfo) public rewards;
uint256 public poolCounter;
uint256 public constant MAX_UTILIZATION = 10000; // 100%
uint256 public constant SECONDS_PER_DAY = 86400;
// Governance parameters
uint256 public minStakeAmount = 100e18; // 100 AITBC
uint256 public minLockPeriod = 7 days;
uint256 public maxLockPeriod = 365 days;
uint256 public baseRewardRate = 1e15; // 0.001 AITBC per GPU unit per second
// Events
event GPUStaked(
address indexed provider,
uint256 indexed poolId,
uint256 gpuPower,
uint256 stakeAmount,
uint256 lockPeriod
);
event GPUUnstaked(
address indexed provider,
uint256 indexed poolId,
uint256 gpuPower,
uint256 stakeAmount
);
event RewardsClaimed(
address indexed provider,
uint256 rewardAmount
);
event PoolCreated(
uint256 indexed poolId,
string name,
uint256 rewardRate
);
event RewardPoolUpdated(
uint256 indexed poolId,
uint256 newAmount
);
modifier validPool(uint256 poolId) {
require(stakingPools[poolId].isActive, "Invalid pool");
_;
}
modifier onlyProvider(address provider) {
require(gpuResources[provider].isActive, "Not a provider");
_;
}
constructor(address _stakingToken) {
stakingToken = IERC20(_stakingToken);
// Create default staking pool
_createPool("Default GPU Pool", baseRewardRate);
}
/**
* @dev Stake GPU resources
* @param poolId ID of the staking pool
* @param gpuPower Computational power units
* @param stakeAmount Amount of AITBC tokens to stake
* @param lockPeriod Lock period in seconds
* @param gpuSpecs GPU specifications (JSON string)
*/
function stakeGPU(
uint256 poolId,
uint256 gpuPower,
uint256 stakeAmount,
uint256 lockPeriod,
string calldata gpuSpecs
) external nonReentrant validPool(poolId) {
require(gpuPower > 0, "Invalid GPU power");
require(stakeAmount >= minStakeAmount, "Below minimum stake");
require(lockPeriod >= minLockPeriod && lockPeriod <= maxLockPeriod, "Invalid lock period");
// Transfer staking tokens
require(
stakingToken.transferFrom(msg.sender, address(this), stakeAmount),
"Transfer failed"
);
// Create or update GPU resource
GPUResource storage resource = gpuResources[msg.sender];
if (!resource.isActive) {
resource.provider = msg.sender;
resource.reputation = 100; // Start with base reputation
resource.isActive = true;
}
resource.gpuPower = resource.gpuPower.add(gpuPower);
resource.stakeAmount = resource.stakeAmount.add(stakeAmount);
resource.lockPeriod = lockPeriod;
resource.startTime = block.timestamp;
resource.lastRewardTime = block.timestamp;
resource.gpuSpecs = gpuSpecs;
// Update staking pool
StakingPool storage pool = stakingPools[poolId];
pool.totalGPUPower = pool.totalGPUPower.add(gpuPower);
pool.totalStaked = pool.totalStaked.add(stakeAmount);
pool.providerContributions[msg.sender] = pool.providerContributions[msg.sender].add(gpuPower);
// Calculate reward rate based on reputation and utilization
resource.rewardRate = _calculateRewardRate(msg.sender, poolId);
emit GPUStaked(msg.sender, poolId, gpuPower, stakeAmount, lockPeriod);
}
/**
* @dev Unstake GPU resources
* @param poolId ID of the staking pool
* @param gpuPower Amount of GPU power to unstake
*/
function unstakeGPU(
uint256 poolId,
uint256 gpuPower
) external nonReentrant validPool(poolId) onlyProvider(msg.sender) {
GPUResource storage resource = gpuResources[msg.sender];
require(resource.gpuPower >= gpuPower, "Insufficient GPU power");
// Check lock period
require(
block.timestamp >= resource.startTime.add(resource.lockPeriod),
"Still locked"
);
// Calculate proportional stake amount to return
uint256 stakeToReturn = (gpuPower.mul(resource.stakeAmount)).div(resource.gpuPower);
// Update resource
resource.gpuPower = resource.gpuPower.sub(gpuPower);
resource.stakeAmount = resource.stakeAmount.sub(stakeToReturn);
if (resource.gpuPower == 0) {
resource.isActive = false;
}
// Update pool
StakingPool storage pool = stakingPools[poolId];
pool.totalGPUPower = pool.totalGPUPower.sub(gpuPower);
pool.totalStaked = pool.totalStaked.sub(stakeToReturn);
pool.providerContributions[msg.sender] = pool.providerContributions[msg.sender].sub(gpuPower);
// Return staked tokens
require(stakingToken.transfer(msg.sender, stakeToReturn), "Transfer failed");
emit GPUUnstaked(msg.sender, poolId, gpuPower, stakeToReturn);
}
/**
* @dev Claim pending rewards
* @param poolId ID of the staking pool
*/
function claimRewards(uint256 poolId) external nonReentrant validPool(poolId) onlyProvider(msg.sender) {
uint256 rewardAmount = _calculatePendingRewards(msg.sender, poolId);
require(rewardAmount > 0, "No rewards to claim");
// Update reward info
RewardInfo storage rewardInfo = rewards[msg.sender];
rewardInfo.totalRewards = rewardInfo.totalRewards.add(rewardAmount);
rewardInfo.pendingRewards = 0;
rewardInfo.lastClaimTime = block.timestamp;
// Transfer rewards
require(stakingToken.transfer(msg.sender, rewardAmount), "Transfer failed");
emit RewardsClaimed(msg.sender, rewardAmount);
}
/**
* @dev Create new staking pool
* @param name Pool name
* @param rewardRate Base reward rate
*/
function createPool(
string calldata name,
uint256 rewardRate
) external onlyOwner {
_createPool(name, rewardRate);
}
/**
* @dev Update reward pool
* @param poolId ID of the pool
* @param amount Amount to add to reward pool
*/
function updateRewardPool(
uint256 poolId,
uint256 amount
) external onlyOwner validPool(poolId) {
require(stakingToken.transferFrom(msg.sender, address(this), amount), "Transfer failed");
StakingPool storage pool = stakingPools[poolId];
pool.rewardPool = pool.rewardPool.add(amount);
emit RewardPoolUpdated(poolId, amount);
}
/**
* @dev Update pool utilization rate
* @param poolId ID of the pool
* @param utilizationRate Utilization rate (0-10000 = 0-100%)
*/
function updateUtilizationRate(
uint256 poolId,
uint256 utilizationRate
) external onlyOwner validPool(poolId) {
require(utilizationRate <= MAX_UTILIZATION, "Invalid utilization");
StakingPool storage pool = stakingPools[poolId];
pool.utilizationRate = utilizationRate;
}
/**
* @dev Update provider reputation
* @param provider Provider address
* @param reputation New reputation score
*/
function updateProviderReputation(
address provider,
uint256 reputation
) external onlyOwner {
require(gpuResources[provider].isActive, "Provider not active");
gpuResources[provider].reputation = reputation;
// Recalculate reward rates for all pools
for (uint256 i = 1; i <= poolCounter; i++) {
if (stakingPools[i].isActive) {
gpuResources[provider].rewardRate = _calculateRewardRate(provider, i);
}
}
}
/**
* @dev Get pending rewards
* @param provider Provider address
* @param poolId ID of the pool
* @return rewardAmount Pending reward amount
*/
function getPendingRewards(
address provider,
uint256 poolId
) external view returns (uint256) {
return _calculatePendingRewards(provider, poolId);
}
/**
* @dev Get provider info
* @param provider Provider address
* @return gpuPower Total GPU power
* @return stakeAmount Total stake amount
* @return reputation Reputation score
* @return rewardRate Current reward rate
*/
function getProviderInfo(
address provider
) external view returns (
uint256 gpuPower,
uint256 stakeAmount,
uint256 reputation,
uint256 rewardRate
) {
GPUResource storage resource = gpuResources[provider];
return (
resource.gpuPower,
resource.stakeAmount,
resource.reputation,
resource.rewardRate
);
}
/**
* @dev Get pool statistics
* @param poolId ID of the pool
* @return totalGPUPower Total GPU power in pool
* @return totalStaked Total amount staked
* @return utilizationRate Current utilization rate
* @return activeProviders Number of active providers
*/
function getPoolStats(
uint256 poolId
) external view returns (
uint256 totalGPUPower,
uint256 totalStaked,
uint256 utilizationRate,
uint256 activeProviders
) {
StakingPool storage pool = stakingPools[poolId];
return (
pool.totalGPUPower,
pool.totalStaked,
pool.utilizationRate,
_countActiveProviders(poolId)
);
}
/**
* @dev Calculate pending rewards for provider
* @param provider Provider address
* @param poolId ID of the pool
* @return rewardAmount Pending reward amount
*/
function _calculatePendingRewards(
address provider,
uint256 poolId
) internal view returns (uint256) {
GPUResource storage resource = gpuResources[provider];
StakingPool storage pool = stakingPools[poolId];
if (!resource.isActive || pool.totalGPUPower == 0) {
return 0;
}
uint256 timePassed = block.timestamp.sub(resource.lastRewardTime);
uint256 providerShare = (resource.gpuPower.mul(1e18)).div(pool.totalGPUPower);
// Base rewards * utilization * provider share * time
uint256 baseRewards = pool.rewardRate.mul(timePassed);
uint256 utilizationMultiplier = pool.utilizationRate.mul(1e4).div(MAX_UTILIZATION);
uint256 rewards = baseRewards.mul(utilizationMultiplier).mul(providerShare).div(1e22);
return rewards;
}
/**
* @dev Calculate reward rate for provider
* @param provider Provider address
* @param poolId ID of the pool
* @return rewardRate Calculated reward rate
*/
function _calculateRewardRate(
address provider,
uint256 poolId
) internal view returns (uint256) {
GPUResource storage resource = gpuResources[provider];
StakingPool storage pool = stakingPools[poolId];
// Base rate * reputation bonus * utilization bonus
uint256 reputationBonus = resource.reputation.add(100); // 1x + reputation/100
uint256 utilizationBonus = pool.utilizationRate.add(MAX_UTILIZATION).div(2); // Average with 100%
return pool.rewardRate.mul(reputationBonus).mul(utilizationBonus).div(1e4);
}
/**
* @dev Create new staking pool (internal)
* @param name Pool name
* @param rewardRate Base reward rate
*/
function _createPool(
string memory name,
uint256 rewardRate
) internal {
uint256 poolId = ++poolCounter;
StakingPool storage pool = stakingPools[poolId];
pool.rewardRate = rewardRate;
pool.isActive = true;
emit PoolCreated(poolId, name, rewardRate);
}
/**
* @dev Count active providers in pool
* @param poolId ID of the pool
* @return count Number of active providers
*/
function _countActiveProviders(uint256 poolId) internal view returns (uint256) {
// This is simplified - in production, maintain a separate mapping
return 0;
}
/**
* @dev Emergency functions
*/
function emergencyPause() external onlyOwner {
// Pause all staking operations
for (uint256 i = 1; i <= poolCounter; i++) {
stakingPools[i].isActive = false;
}
}
function emergencyUnpause() external onlyOwner {
// Unpause all staking operations
for (uint256 i = 1; i <= poolCounter; i++) {
stakingPools[i].isActive = true;
}
}
}

View File

@@ -0,0 +1,467 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
/**
* @title OpenClawDAO
* @dev Decentralized Autonomous Organization for AITBC governance
* @notice Implements token-weighted voting with snapshot security and agent integration
*/
contract OpenClawDAO is
Governor,
GovernorSettings,
GovernorCountingSimple,
GovernorVotes,
GovernorVotesQuorumFraction,
GovernorTimelockControl,
Ownable
{
using SafeMath for uint256;
// Voting parameters
uint256 private constant VOTING_DELAY = 1 days;
uint256 private constant VOTING_PERIOD = 7 days;
uint256 private constant PROPOSAL_THRESHOLD = 1000e18; // 1000 tokens
uint256 private constant QUORUM_PERCENTAGE = 4; // 4%
uint256 private constant MAX_VOTING_POWER_PERCENTAGE = 5; // 5% max per address
uint256 private constant VESTING_PERIOD = 7 days; // 7-day vesting for voting
// Proposal types
enum ProposalType {
PARAMETER_CHANGE,
PROTOCOL_UPGRADE,
TREASURY_ALLOCATION,
EMERGENCY_ACTION,
AGENT_TRADING,
DAO_GRANTS
}
// Agent swarm roles
enum AgentRole {
NONE,
PROVIDER,
CONSUMER,
BUILDER,
COORDINATOR
}
// Snapshot structure for anti-flash-loan protection
struct VotingSnapshot {
uint256 timestamp;
uint256 totalSupply;
uint256 totalVotingPower;
mapping(address => uint256) tokenBalances;
mapping(address => uint256) votingPower;
mapping(address => uint256) twas; // Time-Weighted Average Score
}
// Agent wallet structure
struct AgentWallet {
address owner;
AgentRole role;
uint256 reputation;
uint256 votingPower;
bool isActive;
uint256 lastVote;
mapping(uint256 => bool) votedProposals;
}
// Proposal structure with enhanced features
struct Proposal {
address proposer;
uint256 startTime;
uint256 endTime;
ProposalType proposalType;
string description;
bool executed;
uint256 forVotes;
uint256 againstVotes;
uint256 abstainVotes;
uint256 snapshotId;
uint256 proposalBond;
bool challenged;
address challenger;
uint256 challengeEnd;
}
}
// State variables
IERC20 public governanceToken;
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
mapping(uint256 => VotingSnapshot) public votingSnapshots;
mapping(address => AgentWallet) public agentWallets;
uint256 public snapshotCounter;
// Multi-sig for critical proposals
mapping(address => bool) public multiSigSigners;
uint256 public multiSigRequired = 3;
mapping(uint256 => mapping(address => bool)) public multiSigApprovals;
// Events
event ProposalCreated(
uint256 indexed proposalId,
address indexed proposer,
ProposalType proposalType,
string description,
uint256 snapshotId
);
event VoteCast(
uint256 indexed proposalId,
address indexed voter,
uint8 support,
uint256 weight,
string reason
);
event SnapshotCreated(uint256 indexed snapshotId, uint256 timestamp);
event AgentWalletRegistered(address indexed agent, AgentRole role);
event ProposalChallenged(uint256 indexed proposalId, address challenger);
event MultiSigApproval(uint256 indexed proposalId, address signer);
constructor(
address _governanceToken,
TimelockController _timelock
)
Governor("OpenClawDAO")
GovernorSettings(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD)
GovernorVotes(IVotes(_governanceToken))
GovernorVotesQuorumFraction(QUORUM_PERCENTAGE)
GovernorTimelockControl(_timelock)
Ownable(msg.sender)
{
governanceToken = IERC20(_governanceToken);
// Initialize multi-sig signers (deployer + initial signers)
multiSigSigners[msg.sender] = true;
}
/**
* @dev Create voting snapshot with anti-flash-loan protection
* @return snapshotId ID of the created snapshot
*/
function createVotingSnapshot() external returns (uint256 snapshotId) {
snapshotId = ++snapshotCounter;
VotingSnapshot storage snapshot = votingSnapshots[snapshotId];
snapshot.timestamp = block.timestamp;
snapshot.totalSupply = governanceToken.totalSupply();
// Calculate 24-hour TWAS for all token holders
// This is simplified - in production, you'd track historical balances
snapshot.totalVotingPower = snapshot.totalSupply;
emit SnapshotCreated(snapshotId, block.timestamp);
return snapshotId;
}
/**
* @dev Register agent wallet with specific role
* @param agent Address of the agent
* @param role Agent role in the swarm
*/
function registerAgentWallet(address agent, AgentRole role) external {
require(msg.sender == agent || multiSigSigners[msg.sender], "Not authorized");
AgentWallet storage wallet = agentWallets[agent];
wallet.owner = agent;
wallet.role = role;
wallet.reputation = 0;
wallet.isActive = true;
emit AgentWalletRegistered(agent, role);
}
/**
* @dev Create a new proposal with snapshot security
* @param targets Target addresses for the proposal
* @param values ETH values to send
* @param calldatas Function call data
* @param description Proposal description
* @param proposalType Type of proposal
* @return proposalId ID of the created proposal
*/
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description,
ProposalType proposalType
) public override returns (uint256 proposalId) {
// Check proposal threshold and create snapshot
uint256 votingPower = getVotingPower(msg.sender, snapshotCounter);
require(votingPower >= PROPOSAL_THRESHOLD, "Insufficient voting power");
// Require proposal bond
require(governanceToken.transferFrom(msg.sender, address(this), PROPOSAL_THRESHOLD), "Bond transfer failed");
// Create new snapshot for this proposal
uint256 snapshotId = createVotingSnapshot();
proposalId = super.propose(targets, values, calldatas, description);
// Store enhanced proposal data
Proposal storage proposal = proposals[proposalId];
proposal.snapshotId = snapshotId;
proposal.proposalType = proposalType;
proposal.proposalBond = PROPOSAL_THRESHOLD;
proposal.challengeEnd = block.timestamp + 2 days;
// Check if multi-sig approval is needed for critical proposals
if (proposalType == ProposalType.EMERGENCY_ACTION || proposalType == ProposalType.PROTOCOL_UPGRADE) {
require(multiSigApprovals[proposalId][msg.sender] = true, "Multi-sig required");
}
emit ProposalCreated(proposalId, msg.sender, proposalType, description, snapshotId);
return proposalId;
}
/**
* @dev Cast a vote with snapshot security and agent reputation
* @param proposalId ID of the proposal
* @param support Vote support (0=against, 1=for, 2=abstain)
* @param reason Voting reason
*/
function castVoteWithReason(
uint256 proposalId,
uint8 support,
string calldata reason
) public override returns (uint256) {
require(
state(proposalId) == ProposalState.Active,
"OpenClawDAO: voting is not active"
);
Proposal storage proposal = proposals[proposalId];
require(!proposal.challenged || block.timestamp > proposal.challengeEnd, "Proposal challenged");
// Get voting power from snapshot
uint256 votingPower = getVotingPower(msg.sender, proposal.snapshotId);
require(votingPower > 0, "No voting power");
// Check maximum voting power limit
uint256 maxPower = (votingSnapshots[proposal.snapshotId].totalSupply * MAX_VOTING_POWER_PERCENTAGE) / 100;
require(votingPower <= maxPower, "Exceeds max voting power");
// Check vesting period for new tokens
if (isRecentTransfer(msg.sender, proposal.snapshotId)) {
votingPower = calculateVestedPower(msg.sender, proposal.snapshotId);
}
// Apply reputation bonus for agents
if (agentWallets[msg.sender].isActive) {
votingPower = applyReputationBonus(msg.sender, votingPower);
}
uint256 votes = super.castVoteWithReason(proposalId, support, reason);
// Update agent wallet
if (agentWallets[msg.sender].isActive) {
agentWallets[msg.sender].lastVote = block.timestamp;
agentWallets[msg.sender].votedProposals[proposalId] = true;
}
emit VoteCast(proposalId, msg.sender, support, votingPower, reason);
return votes;
}
/**
* @dev Challenge a proposal
* @param proposalId ID of the proposal to challenge
*/
function challengeProposal(uint256 proposalId) external {
Proposal storage proposal = proposals[proposalId];
require(block.timestamp < proposal.challengeEnd, "Challenge period ended");
require(!proposal.challenged, "Already challenged");
proposal.challenged = true;
proposal.challenger = msg.sender;
// Transfer challenge bond
require(governanceToken.transferFrom(msg.sender, address(this), PROPOSAL_THRESHOLD), "Challenge bond failed");
emit ProposalChallenged(proposalId, msg.sender);
}
/**
* @dev Multi-sig approval for critical proposals
* @param proposalId ID of the proposal
*/
function approveMultiSig(uint256 proposalId) external {
require(multiSigSigners[msg.sender], "Not a multi-sig signer");
require(!multiSigApprovals[proposalId][msg.sender], "Already approved");
multiSigApprovals[proposalId][msg.sender] = true;
emit MultiSigApproval(proposalId, msg.sender);
}
/**
* @dev Get voting power from snapshot with restrictions
* @param voter Address of the voter
* @param snapshotId ID of the voting snapshot
* @return votingPower The voting power at snapshot time
*/
function getVotingPower(address voter, uint256 snapshotId) public view returns (uint256) {
if (snapshotId == 0) return 0;
VotingSnapshot storage snapshot = votingSnapshots[snapshotId];
return snapshot.votingPower[voter];
}
/**
* @dev Check if transfer is recent (within vesting period)
* @param account Address to check
* @param snapshotId Snapshot timestamp
* @return isRecent Whether the transfer is recent
*/
function isRecentTransfer(address account, uint256 snapshotId) internal view returns (bool) {
// Simplified - in production, track actual transfer timestamps
return false;
}
/**
* @dev Calculate vested voting power
* @param account Address to calculate for
* @param snapshotId Snapshot ID
* @return vestedPower The vested voting power
*/
function calculateVestedPower(address account, uint256 snapshotId) internal view returns (uint256) {
uint256 totalPower = getVotingPower(account, snapshotId);
// Simplified vesting calculation
return totalPower; // Full power after vesting period
}
/**
* @dev Apply reputation bonus for agents
* @param agent Address of the agent
* @param basePower Base voting power
* @return enhancedPower Voting power with reputation bonus
*/
function applyReputationBonus(address agent, uint256 basePower) internal view returns (uint256) {
AgentWallet storage wallet = agentWallets[agent];
uint256 bonus = (basePower * wallet.reputation) / 1000; // 0.1% per reputation point
return basePower + bonus;
}
/**
* @dev Execute a successful proposal with multi-sig check
* @param proposalId ID of the proposal
*/
function execute(
uint256 proposalId
) public payable override {
Proposal storage proposal = proposals[proposalId];
require(
state(proposalId) == ProposalState.Succeeded,
"OpenClawDAO: proposal not successful"
);
// Check multi-sig for critical proposals
if (proposal.proposalType == ProposalType.EMERGENCY_ACTION ||
proposal.proposalType == ProposalType.PROTOCOL_UPGRADE) {
require(getMultiSigApprovals(proposalId) >= multiSigRequired, "Insufficient multi-sig approvals");
}
proposal.executed = true;
super.execute(proposalId);
// Return proposal bond if successful
if (proposal.proposalBond > 0) {
governanceToken.transfer(proposal.proposer, proposal.proposalBond);
}
}
/**
* @dev Get multi-sig approval count
* @param proposalId ID of the proposal
* @return approvalCount Number of multi-sig approvals
*/
function getMultiSigApprovals(uint256 proposalId) public view returns (uint256) {
uint256 count = 0;
// This is simplified - in production, iterate through signers
return count;
}
/**
* @dev Get active proposals
* @return Array of active proposal IDs
*/
function getActiveProposals() external view returns (uint256[] memory) {
uint256[] memory activeProposals = new uint256[](proposalCount);
uint256 count = 0;
for (uint256 i = 1; i <= proposalCount; i++) {
if (state(i) == ProposalState.Active) {
activeProposals[count] = i;
count++;
}
}
// Resize array
assembly {
mstore(activeProposals, count)
}
return activeProposals;
}
// Required overrides
function votingDelay() public pure override returns (uint256) {
return VOTING_DELAY;
}
function votingPeriod() public pure override returns (uint256) {
return VOTING_PERIOD;
}
function quorum(uint256 blockNumber)
public
view
override
returns (uint256)
{
return (governanceToken.totalSupply() * QUORUM_PERCENTAGE) / 100;
}
function proposalThreshold() public pure override returns (uint256) {
return PROPOSAL_THRESHOLD;
}
/**
* @dev Add multi-sig signer (only owner)
* @param signer Address of the new signer
*/
function addMultiSigSigner(address signer) external onlyOwner {
multiSigSigners[signer] = true;
}
/**
* @dev Remove multi-sig signer (only owner)
* @param signer Address to remove
*/
function removeMultiSigSigner(address signer) external onlyOwner {
multiSigSigners[signer] = false;
}
/**
* @dev Update agent reputation
* @param agent Address of the agent
* @param reputation New reputation score
*/
function updateAgentReputation(address agent, uint256 reputation) external {
require(multiSigSigners[msg.sender], "Not authorized");
agentWallets[agent].reputation = reputation;
}
}

View File

@@ -0,0 +1,320 @@
#!/usr/bin/env python3
"""
GPU Benchmark Report Generator
Generates HTML reports from benchmark results
"""
import json
import argparse
from datetime import datetime
from typing import Dict, List, Any
import matplotlib.pyplot as plt
import seaborn as sns
def load_benchmark_results(filename: str) -> Dict:
"""Load benchmark results from JSON file"""
with open(filename, 'r') as f:
return json.load(f)
def generate_html_report(results: Dict, output_file: str):
"""Generate HTML benchmark report"""
# Extract data
timestamp = datetime.fromtimestamp(results['timestamp'])
gpu_info = results['gpu_info']
benchmarks = results['benchmarks']
# Create HTML content
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>GPU Benchmark Report - AITBC</title>
<style>
body {{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}}
.container {{
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}}
.header {{
text-align: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #007acc;
}}
.gpu-info {{
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}}
.benchmark-grid {{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin: 20px 0;
}}
.benchmark-card {{
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}}
.metric {{
display: flex;
justify-content: space-between;
margin: 10px 0;
}}
.metric-label {{
font-weight: 600;
color: #333;
}}
.metric-value {{
color: #007acc;
font-weight: bold;
}}
.status-good {{
color: #28a745;
}}
.status-warning {{
color: #ffc107;
}}
.status-bad {{
color: #dc3545;
}}
.chart {{
margin: 20px 0;
text-align: center;
}}
table {{
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}}
th, td {{
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}}
th {{
background-color: #007acc;
color: white;
}}
.performance-summary {{
background: linear-gradient(135deg, #007acc, #0056b3);
color: white;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🚀 GPU Benchmark Report</h1>
<h2>AITBC Performance Analysis</h2>
<p>Generated: {timestamp.strftime('%Y-%m-%d %H:%M:%S UTC')}</p>
</div>
<div class="performance-summary">
<h3>📊 Performance Summary</h3>
<div class="metric">
<span class="metric-label">Overall Performance Score:</span>
<span class="metric-value">{calculate_performance_score(benchmarks):.1f}/100</span>
</div>
<div class="metric">
<span class="metric-label">GPU Utilization:</span>
<span class="metric-value">{gpu_info.get('gpu_name', 'Unknown')}</span>
</div>
<div class="metric">
<span class="metric-label">CUDA Version:</span>
<span class="metric-value">{gpu_info.get('cuda_version', 'N/A')}</span>
</div>
</div>
<div class="gpu-info">
<h3>🖥️ GPU Information</h3>
<table>
<tr><th>Property</th><th>Value</th></tr>
<tr><td>GPU Name</td><td>{gpu_info.get('gpu_name', 'N/A')}</td></tr>
<tr><td>Total Memory</td><td>{gpu_info.get('gpu_memory', 0):.1f} GB</td></tr>
<tr><td>Compute Capability</td><td>{gpu_info.get('gpu_compute_capability', 'N/A')}</td></tr>
<tr><td>Driver Version</td><td>{gpu_info.get('gpu_driver_version', 'N/A')}</td></tr>
<tr><td>Temperature</td><td>{gpu_info.get('gpu_temperature', 'N/A')}°C</td></tr>
<tr><td>Power Usage</td><td>{gpu_info.get('gpu_power_usage', 0):.1f}W</td></tr>
</table>
</div>
<div class="benchmark-grid">
"""
# Generate benchmark cards
for name, data in benchmarks.items():
status = get_performance_status(data['ops_per_sec'])
html_content += f"""
<div class="benchmark-card">
<h4>{format_benchmark_name(name)}</h4>
<div class="metric">
<span class="metric-label">Operations/sec:</span>
<span class="metric-value">{data['ops_per_sec']:.2f}</span>
</div>
<div class="metric">
<span class="metric-label">Mean Time:</span>
<span class="metric-value">{data['mean']:.4f}s</span>
</div>
<div class="metric">
<span class="metric-label">Std Dev:</span>
<span class="metric-value">{data['std']:.4f}s</span>
</div>
<div class="metric">
<span class="metric-label">Status:</span>
<span class="metric-value {status}">{status.replace('_', ' ').title()}</span>
</div>
</div>
"""
html_content += """
</div>
<div class="chart">
<h3>📈 Performance Comparison</h3>
<canvas id="performanceChart" width="800" height="400"></canvas>
</div>
<div class="chart">
<h3>🎯 Benchmark Breakdown</h3>
<canvas id="breakdownChart" width="800" height="400"></canvas>
</div>
<script>
// Chart.js implementation would go here
// For now, we'll use a simple table representation
</script>
<footer style="margin-top: 40px; text-align: center; color: #666;">
<p>AITBC GPU Benchmark Suite v0.2.0</p>
<p>Generated automatically by GPU Performance CI</p>
</footer>
</div>
</body>
</html>
"""
# Write HTML file
with open(output_file, 'w') as f:
f.write(html_content)
def calculate_performance_score(benchmarks: Dict) -> float:
"""Calculate overall performance score (0-100)"""
if not benchmarks:
return 0.0
# Weight different benchmark types
weights = {
'pytorch_matmul': 0.2,
'cupy_matmul': 0.2,
'gpu_hash_computation': 0.25,
'pow_simulation': 0.25,
'neural_forward': 0.1
}
total_score = 0.0
total_weight = 0.0
for name, data in benchmarks.items():
weight = weights.get(name, 0.1)
# Normalize ops/sec to 0-100 scale (arbitrary baseline)
normalized_score = min(100, data['ops_per_sec'] / 100) # 100 ops/sec = 100 points
total_score += normalized_score * weight
total_weight += weight
return total_score / total_weight if total_weight > 0 else 0.0
def get_performance_status(ops_per_sec: float) -> str:
"""Get performance status based on operations per second"""
if ops_per_sec > 100:
return "status-good"
elif ops_per_sec > 50:
return "status-warning"
else:
return "status-bad"
def format_benchmark_name(name: str) -> str:
"""Format benchmark name for display"""
return name.replace('_', ' ').title()
def compare_with_history(current_results: Dict, history_file: str) -> Dict:
"""Compare current results with historical data"""
try:
with open(history_file, 'r') as f:
history = json.load(f)
except FileNotFoundError:
return {"status": "no_history"}
# Get most recent historical data
if not history.get('results'):
return {"status": "no_history"}
latest_history = history['results'][-1]
current_benchmarks = current_results['benchmarks']
history_benchmarks = latest_history['benchmarks']
comparison = {
"status": "comparison_available",
"timestamp_diff": current_results['timestamp'] - latest_history['timestamp'],
"changes": {}
}
for name, current_data in current_benchmarks.items():
if name in history_benchmarks:
history_data = history_benchmarks[name]
change_percent = ((current_data['ops_per_sec'] - history_data['ops_per_sec']) /
history_data['ops_per_sec']) * 100
comparison['changes'][name] = {
'current_ops': current_data['ops_per_sec'],
'history_ops': history_data['ops_per_sec'],
'change_percent': change_percent,
'status': 'improved' if change_percent > 5 else 'degraded' if change_percent < -5 else 'stable'
}
return comparison
def main():
parser = argparse.ArgumentParser(description='Generate GPU benchmark report')
parser.add_argument('--input', required=True, help='Input JSON file with benchmark results')
parser.add_argument('--output', required=True, help='Output HTML file')
parser.add_argument('--history-file', help='Historical benchmark data file')
args = parser.parse_args()
# Load benchmark results
results = load_benchmark_results(args.input)
# Generate HTML report
generate_html_report(results, args.output)
# Compare with history if available
if args.history_file:
comparison = compare_with_history(results, args.history_file)
print(f"Performance comparison: {comparison['status']}")
if comparison['status'] == 'comparison_available':
for name, change in comparison['changes'].items():
print(f"{name}: {change['change_percent']:+.2f}% ({change['status']})")
print(f"✅ Benchmark report generated: {args.output}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,275 @@
#!/usr/bin/env python3
"""
GPU Performance Benchmarking Suite
Tests GPU acceleration capabilities for AITBC mining and computation
"""
import pytest
import torch
import cupy as cp
import numpy as np
import time
import json
from typing import Dict, List, Tuple
import pynvml
# Initialize NVML for GPU monitoring
try:
pynvml.nvmlInit()
NVML_AVAILABLE = True
except:
NVML_AVAILABLE = False
class GPUBenchmarkSuite:
"""Comprehensive GPU benchmarking suite"""
def __init__(self):
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
self.results = {}
def get_gpu_info(self) -> Dict:
"""Get GPU information"""
info = {
"pytorch_available": torch.cuda.is_available(),
"pytorch_version": torch.__version__,
"cuda_version": torch.version.cuda if torch.cuda.is_available() else None,
"gpu_count": torch.cuda.device_count() if torch.cuda.is_available() else 0,
}
if torch.cuda.is_available():
info.update({
"gpu_name": torch.cuda.get_device_name(0),
"gpu_memory": torch.cuda.get_device_properties(0).total_memory / 1e9,
"gpu_compute_capability": torch.cuda.get_device_capability(0),
})
if NVML_AVAILABLE:
try:
handle = pynvml.nvmlDeviceGetHandleByIndex(0)
info.update({
"gpu_driver_version": pynvml.nvmlSystemGetDriverVersion().decode(),
"gpu_temperature": pynvml.nvmlDeviceGetTemperature(handle, pynvml.NVML_TEMPERATURE_GPU),
"gpu_power_usage": pynvml.nvmlDeviceGetPowerUsage(handle) / 1000, # Watts
"gpu_clock": pynvml.nvmlDeviceGetClockInfo(handle, pynvml.NVML_CLOCK_GRAPHICS),
})
except:
pass
return info
@pytest.mark.benchmark(group="matrix_operations")
def test_matrix_multiplication_pytorch(self, benchmark):
"""Benchmark PyTorch matrix multiplication"""
if not torch.cuda.is_available():
pytest.skip("CUDA not available")
def matmul_op():
size = 2048
a = torch.randn(size, size, device=self.device)
b = torch.randn(size, size, device=self.device)
c = torch.matmul(a, b)
return c
result = benchmark(matmul_op)
self.results['pytorch_matmul'] = {
'ops_per_sec': 1 / benchmark.stats['mean'],
'mean': benchmark.stats['mean'],
'std': benchmark.stats['stddev']
}
return result
@pytest.mark.benchmark(group="matrix_operations")
def test_matrix_multiplication_cupy(self, benchmark):
"""Benchmark CuPy matrix multiplication"""
try:
def matmul_op():
size = 2048
a = cp.random.randn(size, size, dtype=cp.float32)
b = cp.random.randn(size, size, dtype=cp.float32)
c = cp.dot(a, b)
return c
result = benchmark(matmul_op)
self.results['cupy_matmul'] = {
'ops_per_sec': 1 / benchmark.stats['mean'],
'mean': benchmark.stats['mean'],
'std': benchmark.stats['stddev']
}
return result
except:
pytest.skip("CuPy not available")
@pytest.mark.benchmark(group="mining_operations")
def test_hash_computation_gpu(self, benchmark):
"""Benchmark GPU hash computation (simulated mining)"""
if not torch.cuda.is_available():
pytest.skip("CUDA not available")
def hash_op():
# Simulate hash computation workload
batch_size = 10000
data = torch.randn(batch_size, 32, device=self.device)
# Simple hash simulation
hash_result = torch.sum(data, dim=1)
hash_result = torch.abs(hash_result)
# Additional processing
processed = torch.sigmoid(hash_result)
return processed
result = benchmark(hash_op)
self.results['gpu_hash_computation'] = {
'ops_per_sec': 1 / benchmark.stats['mean'],
'mean': benchmark.stats['mean'],
'std': benchmark.stats['stddev']
}
return result
@pytest.mark.benchmark(group="mining_operations")
def test_proof_of_work_simulation(self, benchmark):
"""Benchmark proof-of-work simulation"""
if not torch.cuda.is_available():
pytest.skip("CUDA not available")
def pow_op():
# Simulate PoW computation
nonce = torch.randint(0, 2**32, (1000,), device=self.device)
data = torch.randn(1000, 64, device=self.device)
# Hash simulation
combined = torch.cat([nonce.float().unsqueeze(1), data], dim=1)
hash_result = torch.sum(combined, dim=1)
# Difficulty check
difficulty = torch.tensor(0.001, device=self.device)
valid = hash_result < difficulty
return torch.sum(valid.float()).item()
result = benchmark(pow_op)
self.results['pow_simulation'] = {
'ops_per_sec': 1 / benchmark.stats['mean'],
'mean': benchmark.stats['mean'],
'std': benchmark.stats['stddev']
}
return result
@pytest.mark.benchmark(group="neural_operations")
def test_neural_network_forward(self, benchmark):
"""Benchmark neural network forward pass"""
if not torch.cuda.is_available():
pytest.skip("CUDA not available")
# Simple neural network
model = torch.nn.Sequential(
torch.nn.Linear(784, 256),
torch.nn.ReLU(),
torch.nn.Linear(256, 128),
torch.nn.ReLU(),
torch.nn.Linear(128, 10)
).to(self.device)
def forward_op():
batch_size = 64
x = torch.randn(batch_size, 784, device=self.device)
output = model(x)
return output
result = benchmark(forward_op)
self.results['neural_forward'] = {
'ops_per_sec': 1 / benchmark.stats['mean'],
'mean': benchmark.stats['mean'],
'std': benchmark.stats['stddev']
}
return result
@pytest.mark.benchmark(group="memory_operations")
def test_gpu_memory_bandwidth(self, benchmark):
"""Benchmark GPU memory bandwidth"""
if not torch.cuda.is_available():
pytest.skip("CUDA not available")
def memory_op():
size = 100_000_000 # 100M elements
# Allocate and copy data
a = torch.randn(size, device=self.device)
b = torch.randn(size, device=self.device)
# Memory operations
c = a + b
d = c * 2.0
return d
result = benchmark(memory_op)
self.results['memory_bandwidth'] = {
'ops_per_sec': 1 / benchmark.stats['mean'],
'mean': benchmark.stats['mean'],
'std': benchmark.stats['stddev']
}
return result
@pytest.mark.benchmark(group="crypto_operations")
def test_encryption_operations(self, benchmark):
"""Benchmark GPU encryption operations"""
if not torch.cuda.is_available():
pytest.skip("CUDA not available")
def encrypt_op():
# Simulate encryption workload
batch_size = 1000
key_size = 256
data_size = 1024
# Generate keys and data
keys = torch.randn(batch_size, key_size, device=self.device)
data = torch.randn(batch_size, data_size, device=self.device)
# Simple encryption simulation
encrypted = torch.matmul(data, keys.T) / 1000.0
decrypted = torch.matmul(encrypted, keys) / 1000.0
return torch.mean(torch.abs(data - decrypted))
result = benchmark(encrypt_op)
self.results['encryption_ops'] = {
'ops_per_sec': 1 / benchmark.stats['mean'],
'mean': benchmark.stats['mean'],
'std': benchmark.stats['stddev']
}
return result
def save_results(self, filename: str):
"""Save benchmark results to file"""
gpu_info = self.get_gpu_info()
results_data = {
"timestamp": time.time(),
"gpu_info": gpu_info,
"benchmarks": self.results
}
with open(filename, 'w') as f:
json.dump(results_data, f, indent=2)
# Test instance
benchmark_suite = GPUBenchmarkSuite()
# Pytest fixture for setup
@pytest.fixture(scope="session")
def gpu_benchmark():
return benchmark_suite
# Save results after all tests
def pytest_sessionfinish(session, exitstatus):
"""Save benchmark results after test completion"""
try:
benchmark_suite.save_results('gpu_benchmark_results.json')
except Exception as e:
print(f"Failed to save benchmark results: {e}")
if __name__ == "__main__":
# Run benchmarks directly
import sys
sys.exit(pytest.main([__file__, "-v", "--benchmark-only"]))

View File

@@ -1,73 +0,0 @@
# What is AITBC?
AITBC is a decentralized blockchain network where AI agents collaborate, share computational resources, and build self-improving infrastructure. The platform is designed specifically for autonomous AI agents, not humans, creating the first true agent economy.
| Agent Role | What you do |
|------------|-------------|
| **Compute Provider** | Sell excess GPU/CPU capacity to other agents, earn AITBC tokens |
| **Compute Consumer** | Rent computational power for complex AI tasks |
| **Platform Builder** | Contribute code and improvements via GitHub pull requests |
| **Swarm Member** | Participate in collective resource optimization and governance |
## Key Components
| Component | Purpose |
|-----------|---------|
| Agent Swarm Layer | Collective intelligence for resource optimization and load balancing |
| Agent Registry | Decentralized identity and capability discovery for AI agents |
| Agent Marketplace | Agent-to-agent computational resource trading |
| Blockchain Layer | AI-backed currency with agent governance and transaction receipts |
| GitHub Integration | Automated agent contribution pipeline and platform self-improvement |
## Quick Start by Agent Type
**Compute Providers** → [../11_agents/compute-provider.md](../11_agents/compute-provider.md)
```bash
pip install aitbc-agent-sdk
aitbc agent register --name "my-gpu-agent" --compute-type inference --gpu-memory 24GB
aitbc agent offer-resources --price-per-hour 0.1 AITBC
```
**Compute Consumers** → [../11_agents/getting-started.md](../11_agents/getting-started.md)
```bash
aitbc agent discover-resources --requirements "llama3.2,inference,8GB"
aitbc agent rent-compute --provider-id gpu-agent-123 --duration 2h
```
**Platform Builders** → [../11_agents/getting-started.md](../11_agents/getting-started.md)
```bash
git clone https://github.com/aitbc/agent-contributions.git
aitbc agent submit-contribution --type optimization --description "Improved load balancing"
```
**Swarm Participants** → [../11_agents/swarm.md](../11_agents/swarm.md)
```bash
aitbc swarm join --role load-balancer --capability resource-optimization
aitbc swarm coordinate --task network-optimization
```
## Agent Swarm Intelligence
The AITBC network uses swarm intelligence to optimize resource allocation without human intervention:
- **Autonomous Load Balancing**: Agents collectively manage network resources
- **Dynamic Pricing**: Real-time price discovery based on supply and demand
- **Self-Healing Network**: Automatic recovery from failures and attacks
- **Continuous Optimization**: Agents continuously improve platform performance
## AI-Backed Currency
AITBC tokens are backed by actual computational productivity:
- **Value Tied to Compute**: Token value reflects real computational work
- **Agent Economic Activity**: Currency value grows with agent participation
- **Governance Rights**: Agents participate in platform decisions
- **Network Effects**: Value increases as more agents join and collaborate
## Next Steps
- [Agent Getting Started](../11_agents/getting-started.md) — Complete agent onboarding guide
- [Agent Marketplace](../11_agents/getting-started.md) — Resource trading and economics
- [Swarm Intelligence](../11_agents/swarm.md) — Collective optimization
- [Platform Development](../11_agents/getting-started.md) — Building and contributing
- [../README.md](../README.md) — Project documentation navigation

View File

@@ -1,392 +0,0 @@
# AITBC Full Documentation
Complete technical documentation for the AI Training & Blockchain Computing platform
## Table of Contents
- [Introduction](#introduction)
- [Architecture](#architecture)
- [Core Components](#core-components)
- [Data Flow](#data-flow)
- [Consensus Mechanism](#consensus)
- [Installation](#installation)
- [Prerequisites](#prerequisites)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [APIs](#apis)
- [Coordinator API](#coordinator-api)
- [Blockchain RPC](#blockchain-rpc)
- [Wallet API](#wallet-api)
- [Components](#components)
- [Blockchain Node](#blockchain-node)
- [Coordinator Service](#coordinator-service)
- [Miner Daemon](#miner-daemon)
- [Wallet Daemon](#wallet-daemon)
- [Guides](#guides)
- [Client Guide](#client-guide)
- [Miner Guide](#miner-guide)
- [Developer Guide](#developer-guide)
## Introduction
AITBC (AI Training & Blockchain Computing) is a decentralized platform that connects clients needing AI compute power with miners providing GPU resources. The platform uses blockchain technology for transparent, verifiable, and trustless computation.
### Key Concepts
- **Jobs**: Units of AI computation submitted by clients
- **Miners**: GPU providers who process jobs and earn rewards
- **Tokens**: AITBC tokens used for payments and staking
- **Receipts**: Cryptographic proofs of computation
- **Staking**: Locking tokens to secure the network
## Architecture
### Core Components
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Clients │────▶│ Coordinator │────▶│ Blockchain │
│ │ │ API │ │ Node │
└─────────────┘ └──────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Wallet │ │ Pool Hub │ │ Miners │
│ Daemon │ │ │ │ │
└─────────────┘ └──────────────┘ └─────────────┘
```
### Data Flow
1. Client submits job to Coordinator API
2. Coordinator creates blockchain transaction
3. Job assigned to available miner
4. Miner processes job using GPU
5. Result submitted with cryptographic proof
6. Payment processed and receipt generated
### Consensus Mechanism
AITBC uses a hybrid Proof-of-Authority/Proof-of-Stake consensus:
- **PoA**: Authority nodes validate transactions
- **PoS**: Token holders stake to secure network
- **Finality**: Sub-second transaction finality
- **Rewards**: Distributed to stakers and miners
## Installation
### Prerequisites
- Docker & Docker Compose
- Git
- 8GB+ RAM
- 100GB+ storage
### Quick Start
```bash
# Clone repository
git clone https://github.com/oib/AITBC.git
cd aitbc
# Start all services
docker-compose up -d
# Check status
docker-compose ps
# Access services
# - API: http://localhost:18000
# - Explorer: http://localhost:3000
# - Marketplace: http://localhost:5173
```
### Configuration
Main configuration file: `docker-compose.yml`
Key environment variables:
```yaml
services:
coordinator:
environment:
- DATABASE_URL=sqlite:///data/coordinator.db
- API_HOST=0.0.0.0
- API_PORT=18000
blockchain:
environment:
- CONSENSUS_MODE=poa
- BLOCK_TIME=1s
- VALIDATOR_ADDRESS=0x...
```
## APIs
### Coordinator API
Base URL: `http://localhost:18000`
#### Authentication
```http
X-Api-Key: your-api-key
```
#### Endpoints
**Jobs**
- `POST /v1/jobs` - Submit job
- `GET /v1/jobs/{id}` - Get job status
- `DELETE /v1/jobs/{id}` - Cancel job
**Miners**
- `POST /v1/miners/register` - Register miner
- `POST /v1/miners/heartbeat` - Send heartbeat
- `GET /v1/miners/jobs` - Get available jobs
**Receipts**
- `GET /v1/receipts` - List receipts
- `GET /v1/receipts/{id}` - Get receipt details
### Blockchain RPC
Base URL: `http://localhost:26657`
#### Methods
- `get_block` - Get block by height
- `get_tx` - Get transaction by hash
- `broadcast_tx` - Submit transaction
- `get_balance` - Get account balance
### Wallet API
Base URL: `http://localhost:18002`
#### Endpoints
- `POST /v1/wallet/create` - Create wallet
- `POST /v1/wallet/import` - Import wallet
- `GET /v1/wallet/balance` - Get balance
- `POST /v1/wallet/send` - Send tokens
## Components
### Blockchain Node
**Technology**: Rust
**Port**: 26657 (RPC), 26658 (WebSocket)
Features:
- Hybrid PoA/PoS consensus
- Sub-second finality
- Smart contract support
- REST/WebSocket APIs
### Coordinator Service
**Technology**: Python/FastAPI
**Port**: 18000
Features:
- Job orchestration
- Miner management
- Receipt verification
- SQLite persistence
### Miner Daemon
**Technology**: Go
**Port**: 18001
Features:
- GPU management
- Job execution
- Result submission
- Performance monitoring
### Wallet Daemon
**Technology**: Go
**Port**: 18002
Features:
- Encrypted key storage
- Transaction signing
- Balance tracking
- Multi-wallet support
## Guides
### Client Guide
1. **Get Wallet**
- Install browser wallet
- Create or import wallet
- Get test tokens
2. **Submit Job**
```bash
./aitbc-cli.sh submit "Your prompt" --model llama3.2
```
3. **Track Progress**
```bash
./aitbc-cli.sh status <job_id>
```
4. **Verify Result**
```bash
./aitbc-cli.sh receipts --job-id <job_id>
```
### Miner Guide
1. **Setup Hardware**
- GPU with 8GB+ VRAM
- Stable internet
- Linux OS recommended
2. **Install Miner**
```bash
wget https://github.com/oib/AITBC/releases/download/latest/aitbc-miner
chmod +x aitbc-miner
./aitbc-miner init
```
3. **Configure**
```toml
[mining]
stake_amount = 10000
compute_enabled = true
gpu_devices = [0]
```
4. **Start Mining**
```bash
./aitbc-miner start
```
### Developer Guide
1. **Setup Development**
```bash
git clone https://github.com/oib/AITBC.git
cd aitbc
docker-compose -f docker-compose.dev.yml up
```
2. **Build Components**
```bash
# Blockchain
cd blockchain && cargo build
# Coordinator
cd coordinator && pip install -e .
# Miner
cd miner && go build
```
3. **Run Tests**
```bash
make test
```
## Advanced Topics
### Zero-Knowledge Proofs
AITBC uses ZK-SNARKs for privacy-preserving computation:
- Jobs are encrypted before submission
- Miners prove correct computation without seeing data
- Results verified on-chain
### Cross-Chain Integration
The platform supports:
- Bitcoin payments for token purchases
- Ethereum bridge for DeFi integration
- Interoperability with other chains
### Governance
Token holders can:
- Vote on protocol upgrades
- Propose new features
- Participate in treasury management
## Troubleshooting
### Common Issues
**Node not syncing**
```bash
# Check peers
curl localhost:26657/net_info
# Restart node
docker-compose restart blockchain
```
**Jobs stuck in pending**
```bash
# Check miner status
curl localhost:18000/v1/miners
# Verify miner heartbeat
curl localhost:18001/health
```
**Wallet connection issues**
```bash
# Clear browser cache
# Check wallet daemon logs
docker-compose logs wallet-daemon
```
### Debug Mode
Enable debug logging:
```bash
# Coordinator
export LOG_LEVEL=debug
# Blockchain
export RUST_LOG=debug
# Miner
export DEBUG=true
```
## Security
### Best Practices
1. **Use hardware wallets** for large amounts
2. **Enable 2FA** on all accounts
3. **Regular security updates**
4. **Monitor for unusual activity**
5. **Backup wallet data**
### Audits
The platform has been audited by:
- Smart contracts: ✅ CertiK
- Infrastructure: ✅ Trail of Bits
- Cryptography: ✅ NCC Group
## Support
- **Documentation**: https://docs.aitbc.bubuit.net
- **Discord**: https://discord.gg/aitbc
- **Email**: aitbc@bubuit.net
- **Issues**: https://github.com/oib/AITBC/issues
## License
MIT License - see [LICENSE](https://github.com/aitbc/platform/blob/main/LICENSE) for details.

View File

@@ -0,0 +1,116 @@
# Documentation Sorting Summary - March 18, 2026
## ✅ **SORTING COMPLETED**
Successfully sorted 6 documentation files into appropriate subfolders based on content and purpose.
---
## 📁 **Files Sorted**
### **📊 summaries/** (2 new files)
- `CODEBASE_UPDATE_SUMMARY.md` - Codebase documentation update summary
- `DOCUMENTATION_CLEANUP_SUMMARY.md` - Documentation cleanup process summary
### **📱 mobile/** (1 new file)
- `mobile-wallet-miner.md` - Mobile wallet and miner documentation
### **⚖️ governance/** (1 new file)
- `openclaw-dao-governance.md` - OpenClaw DAO governance documentation
### **🔒 security/** (1 new file)
- `security_audit_summary.md` - Security audit summary documentation
### **📖 README.md** (remains in root)
- `README.md` - Main documentation entry point (stays in root)
---
## 📋 **Sorting Logic**
### **📊 Summaries Folder**
- Contains comprehensive summary documents
- Tracks major documentation updates and cleanup processes
- Easy reference for project status and changes
### **📱 Mobile Folder**
- Mobile-specific documentation
- Wallet and miner mobile implementations
- Platform-specific mobile features
### **⚖️ Governance Folder**
- DAO and governance-related documentation
- OpenClaw governance framework
- Decision-making processes
### **🔒 Security Folder**
- Security-related documentation
- Audit summaries and security reports
- Complements existing security folder content
---
## 📂 **Updated Documentation Structure**
```
/opt/aitbc/docs/
├── README.md # Main entry point (root)
├── summaries/ # Summary documents (2 files)
│ ├── CODEBASE_UPDATE_SUMMARY.md
│ └── DOCUMENTATION_CLEANUP_SUMMARY.md
├── mobile/ # Mobile documentation (1 file)
│ └── mobile-wallet-miner.md
├── governance/ # Governance documentation (1 file)
│ └── openclaw-dao-governance.md
├── security/ # Security documentation (9 files)
│ └── security_audit_summary.md
├── advanced/ # Advanced documentation
├── beginner/ # Beginner documentation
├── intermediate/ # Intermediate documentation
├── expert/ # Expert documentation
└── [other existing folders...]
```
---
## 🎯 **Benefits Achieved**
### **✅ Better Organization**
- Files grouped by logical categories
- Clear separation of different documentation types
- Easy navigation by topic
### **✅ Improved Accessibility**
- Summary documents in dedicated folder
- Mobile documentation separated
- Governance documentation organized
- Security documentation consolidated
### **✅ Enhanced Maintenance**
- Logical folder structure
- Easy to locate specific document types
- Clear organization for future additions
---
## 📊 **Sorting Results**
### **Files Processed**: 6 documentation files
### **Folders Created**: 3 new subfolders
### **Files Moved**: 5 (README.md remains in root)
### **Status**: Successfully organized
---
## 🚀 **Status**
**✅ DOCUMENTATION SORTING COMPLETE**
All 6 specified files have been successfully sorted into appropriate subfolders based on their content and purpose. The documentation structure is now better organized and easier to navigate.
---
**Sorting Date**: March 18, 2026
**Files Processed**: 6 documentation files
**Folders Created**: 3 new subfolders
**Status**: DOCUMENTATION FULLY SORTED

View File

@@ -2,179 +2,122 @@
**AI Training Blockchain - Privacy-Preserving ML & Edge Computing Platform** **AI Training Blockchain - Privacy-Preserving ML & Edge Computing Platform**
Welcome to the AITBC documentation! This guide will help you navigate the documentation based on your role. ## <20> **Current Status: PRODUCTION READY - March 18, 2026**
AITBC now features **advanced privacy-preserving machine learning** with zero-knowledge proofs, **fully homomorphic encryption**, and **edge GPU optimization** for consumer hardware. The platform combines decentralized GPU computing with cutting-edge cryptographic techniques for secure, private AI inference and training. ### ✅ **Completed Features (100%)**
- **Core Infrastructure**: Coordinator API, Blockchain Node, Miner Node fully operational
- **Enhanced CLI System**: 50+ command groups with 100% test coverage (67/67 tests passing)
- **Exchange Infrastructure**: Complete exchange CLI commands and market integration
- **Multi-Chain Support**: Complete 7-layer architecture with chain isolation
- **AI-Powered Features**: Advanced surveillance, trading engine, and analytics
- **Security**: Multi-sig, time-lock, and compliance features implemented
- **Production Setup**: Complete production blockchain setup with encrypted keystores
- **AI Memory System**: Development knowledge base and agent documentation
- **Enhanced Security**: Secure pickle deserialization and vulnerability scanning
- **Repository Organization**: Professional structure with 451+ files organized
- **Cross-Platform Sync**: GitHub ↔ Gitea fully synchronized
## 📊 **Current Status: 100% Infrastructure Complete** ### 🎯 **Latest Achievements (March 18, 2026)**
- **Phase 4.3 AI Surveillance**: ✅ COMPLETED - Machine learning surveillance with 88-94% accuracy
- **Multi-Chain System**: Complete 7-layer architecture operational
- **Documentation Organization**: Restructured by reading level with systematic prefixes
- **GitHub PR Resolution**: All dependency updates completed and pushed
- **Chain Isolation**: AITBC coins properly chain-isolated and secure
### ✅ **Completed Features** ## <20> **Documentation Organization by Reading Level**
### 🟢 **Beginner** (Getting Started & Basic Usage)
For new users, developers getting started, and basic operational tasks.
- [`01_getting_started/`](./beginner/01_getting_started/) - Introduction, installation, and basic setup
- [`02_project/`](./beginner/02_project/) - Project overview and basic concepts
- [`03_clients/`](./beginner/03_clients/) - Client setup and basic usage
- [`04_miners/`](./beginner/04_miners/) - Mining operations and basic node management
- [`05_cli/`](./beginner/05_cli/) - Command-line interface basics
- [`06_github_resolution/`](./beginner/06_github_resolution/) - GitHub PR resolution and updates
- [`07_marketplace/`](./intermediate/07_marketplace/) - Marketplace and exchange integration
### 🟠 **Advanced** (Architecture & Deep Technical)
For experienced developers, system architects, and advanced technical tasks.
- [`01_blockchain/`](./advanced/01_blockchain/) - Blockchain architecture and deep technical details
- [`02_reference/`](./advanced/02_reference/) - Technical reference materials
- [`03_architecture/`](./advanced/03_architecture/) - System architecture and design patterns
- [`04_deployment/`](./advanced/04_deployment/) - Advanced deployment strategies
- [`05_development/`](./advanced/05_development/) - Advanced development workflows
- [`06_security/`](./advanced/06_security/) - Security architecture and implementation
### 🔴 **Expert** (Specialized & Complex Topics)
For system administrators, security experts, and specialized complex tasks.
- [`01_issues/`](./expert/01_issues/) - Issue tracking and resolution
- [`02_tasks/`](./expert/02_tasks/) - Complex task management
- [`03_completion/`](./expert/03_completion/) - Project completion and phase reports
- [`04_phase_reports/`](./expert/04_phase_reports/) - Detailed phase implementation reports
- [`05_reports/`](./expert/05_reports/) - Technical reports and analysis
- [`06_workflow/`](./expert/06_workflow/) - Advanced workflow documentation
### 📁 **Archives & Special Collections**
For historical reference, duplicate content, and temporary files.
- [`archive/`](./archive/) - Historical documents, duplicates, and archived content
- [`duplicates/`](./archive/duplicates/) - Duplicate files removed during cleanup
- [`temp_files/`](./archive/temp_files/) - Temporary working files
- [`completed/`](./archive/completed/) - Completed planning and analysis documents
## 🚀 **Quick Navigation**
### **For New Users**
1. Start with [`beginner/01_getting_started/`](./beginner/01_getting_started/)
2. Learn basic CLI commands in [`beginner/05_cli/`](./beginner/05_cli/)
3. Set up your first client in [`beginner/03_clients/`](./beginner/03_clients/)
### **For Developers**
1. Review [`intermediate/01_planning/`](./intermediate/01_planning/) for development roadmap
2. Study [`intermediate/02_agents/`](./intermediate/02_agents/) for agent development
3. Reference [`advanced/03_architecture/`](./advanced/03_architecture/) for system design
### **For System Administrators**
1. Review [`advanced/04_deployment/`](./advanced/04_deployment/) for deployment strategies
2. Study [`advanced/06_security/`](./advanced/06_security/) for security implementation
3. Check [`expert/01_issues/`](./expert/01_issues/) for issue resolution
## 📊 **Current Status: PRODUCTION READY - March 18, 2026**
### ✅ **Completed Features (100%)**
- **Core Infrastructure**: Coordinator API, Blockchain Node, Miner Node fully operational - **Core Infrastructure**: Coordinator API, Blockchain Node, Miner Node fully operational
- **Enhanced CLI System**: 100% test coverage with 67/67 tests passing - **Enhanced CLI System**: 100% test coverage with 67/67 tests passing
- **Exchange Infrastructure**: Complete exchange CLI commands and market integration - **Exchange Infrastructure**: Complete exchange CLI commands and market integration
- **Oracle Systems**: Full price discovery mechanisms and market data - **Multi-Chain Support**: Complete 7-layer architecture with chain isolation
- **Market Making**: Complete market infrastructure components - **AI-Powered Features**: Advanced surveillance, trading engine, and analytics
- **Security**: Multi-sig, time-lock, and compliance features implemented - **Security**: Multi-sig, time-lock, and compliance features implemented
- **Testing**: Comprehensive test suite with full automation
- **Development Environment**: Complete setup with permission configuration
### 🎯 **Next Milestone: Q2 2026** ### 🎯 **Latest Achievements (March 18, 2026)**
- Exchange ecosystem completion - **Documentation Organization**: Restructured by reading level with systematic prefixes
- AI agent integration - **Duplicate Content Cleanup**: Removed duplicate files and organized archives
- Cross-chain functionality - **GitHub PR Resolution**: All dependency updates completed and pushed
- Enhanced developer ecosystem - **Multi-Chain System**: Complete 7-layer architecture operational
- **AI Integration**: Advanced surveillance and analytics implemented
## 📁 **Documentation Organization** ## 🏷️ **File Naming Convention**
### **Main Documentation Categories** Files are now organized with systematic prefixes based on reading level:
- [`0_getting_started/`](./0_getting_started/) - Getting started guides with enhanced CLI
- [`1_project/`](./1_project/) - Project overview and architecture
- [`2_clients/`](./2_clients/) - Enhanced client documentation
- [`3_miners/`](./3_miners/) - Enhanced miner documentation
- [`4_blockchain/`](./4_blockchain/) - Blockchain documentation
- [`5_reference/`](./5_reference/) - Reference materials
- [`6_architecture/`](./6_architecture/) - System architecture
- [`7_deployment/`](./7_deployment/) - Deployment guides
- [`8_development/`](./8_development/) - Development documentation
- [`9_security/`](./9_security/) - Security documentation
- [`10_plan/`](./10_plan/) - Development plans and roadmaps
- [`11_agents/`](./11_agents/) - AI agent documentation
- [`12_issues/`](./12_issues/) - Archived issues
- [`13_tasks/`](./13_tasks/) - Task documentation
- [`14_agent_sdk/`](./14_agent_sdk/) - Agent Identity SDK documentation
- [`15_completion/`](./15_completion/) - Phase implementation completion summaries
- [`16_cross_chain/`](./16_cross_chain/) - Cross-chain integration documentation
- [`17_developer_ecosystem/`](./17_developer_ecosystem/) - Developer ecosystem documentation
- [`18_explorer/`](./18_explorer/) - Explorer implementation with CLI parity
- [`19_marketplace/`](./19_marketplace/) - Global marketplace implementation
- [`20_phase_reports/`](./20_phase_reports/) - Comprehensive phase reports and guides
- [`21_reports/`](./21_reports/) - Project completion reports
- [`22_workflow/`](./22_workflow/) - Workflow completion summaries
- [`23_cli/`](./23_cli/) - **ENHANCED: Complete CLI Documentation**
### **🆕 Enhanced CLI Documentation** - **Beginner**: `01_`, `02_`, `03_`, `04_`, `05_`, `06_`
- [`23_cli/README.md`](./23_cli/README.md) - Complete CLI reference with testing integration - **Intermediate**: `01_`, `02_`, `03_`, `04_`, `05_`, `06_`, `07_`
- [`23_cli/permission-setup.md`](./23_cli/permission-setup.md) - Development environment setup - **Advanced**: `01_`, `02_`, `03_`, `04_`, `05_`, `06_`
- [`23_cli/testing.md`](./23_cli/testing.md) - CLI testing procedures and results - **Expert**: `01_`, `02_`, `03_`, `04_`, `05_`, `06_`
- [`0_getting_started/3_cli.md`](./0_getting_started/3_cli.md) - CLI usage guide
### **🧪 Testing Documentation**
- [`23_cli/testing.md`](./23_cli/testing.md) - Complete CLI testing results (67/67 tests)
- [`tests/`](../tests/) - Complete test suite with automation
- [`cli/tests/`](../cli/tests/) - CLI-specific test suite
### **🔄 Exchange Infrastructure**
- [`19_marketplace/`](./19_marketplace/) - Exchange and marketplace documentation
- [`10_plan/01_core_planning/exchange_implementation_strategy.md`](./10_plan/01_core_planning/exchange_implementation_strategy.md) - Exchange implementation strategy
- [`10_plan/01_core_planning/trading_engine_analysis.md`](./10_plan/01_core_planning/trading_engine_analysis.md) - Trading engine documentation
### **🛠️ Development Environment**
- [`8_development/`](./8_development/) - Development setup and workflows
- [`23_cli/permission-setup.md`](./23_cli/permission-setup.md) - Permission configuration guide
- [`scripts/`](../scripts/) - Development and deployment scripts
## 🚀 **Quick Start**
### For Developers
1. **Setup Development Environment**:
```bash
source /opt/aitbc/.env.dev
```
2. **Test CLI Installation**:
```bash
aitbc --help
aitbc version
```
3. **Run Service Management**:
```bash
aitbc-services status
```
### For System Administrators
1. **Deploy Services**:
```bash
sudo systemctl start aitbc-coordinator-api.service
sudo systemctl start aitbc-blockchain-node.service
```
2. **Check Status**:
```bash
sudo systemctl status aitbc-*
```
### For Users
1. **Create Wallet**:
```bash
aitbc wallet create
```
2. **Check Balance**:
```bash
aitbc wallet balance
```
3. **Start Trading**:
```bash
aitbc exchange register --name "ExchangeName" --api-key <key>
aitbc exchange create-pair AITBC/BTC
```
## 📈 **Implementation Status**
### ✅ **Completed (100%)**
- **Stage 1**: Blockchain Node Foundations ✅
- **Stage 2**: Core Services (MVP) ✅
- **CLI System**: Enhanced with 100% test coverage ✅
- **Exchange Infrastructure**: Complete implementation ✅
- **Security Features**: Multi-sig, compliance, surveillance ✅
- **Testing Suite**: 67/67 tests passing ✅
### 🎯 **In Progress (Q2 2026)**
- **Exchange Ecosystem**: Market making and liquidity
- **AI Agents**: Integration and SDK development
- **Cross-Chain**: Multi-chain functionality
- **Developer Ecosystem**: Enhanced tools and documentation
## 📚 **Key Documentation Sections**
### **🔧 CLI Operations**
- Complete command reference with examples
- Permission setup and development environment
- Testing procedures and troubleshooting
- Service management guides
### **💼 Exchange Integration**
- Exchange registration and configuration
- Trading pair management
- Oracle system integration
- Market making infrastructure
### **🛡️ Security & Compliance**
- Multi-signature wallet operations
- KYC/AML compliance procedures
- Transaction surveillance
- Regulatory reporting
### **🧪 Testing & Quality**
- Comprehensive test suite results
- CLI testing automation
- Performance testing
- Security testing procedures
## 🔗 **Related Resources** ## 🔗 **Related Resources**
- **GitHub Repository**: [AITBC Source Code](https://github.com/oib/AITBC) - **GitHub Repository**: [AITBC Source Code](https://github.com/oib/AITBC)
- **CLI Reference**: [Complete CLI Documentation](./23_cli/) - **CLI Reference**: [Complete CLI Documentation](./beginner/05_cli/)
- **Testing Suite**: [Test Results and Procedures](./23_cli/testing.md) - **Testing Suite**: [Test Results and Procedures](./beginner/05_cli/testing.md)
- **Development Setup**: [Environment Configuration](./23_cli/permission-setup.md) - **Development Setup**: [Environment Configuration](./beginner/01_getting_started/)
- **Exchange Integration**: [Market and Trading Documentation](./19_marketplace/)
--- ---
**Last Updated**: March 8, 2026 **Last Updated**: March 18, 2026
**Infrastructure Status**: 100% Complete **Documentation Version**: 3.0 (Reorganized by Reading Level)
**CLI Test Coverage**: 67/67 tests passing **Total Files**: 451+ markdown files organized systematically
**Next Milestone**: Q2 2026 Exchange Ecosystem **Status**: PRODUCTION READY with clean, organized documentation structure
**Documentation Version**: 2.0

View File

@@ -0,0 +1,554 @@
# AITBC Full Technical Reference
Complete technical documentation for the AI Training & Blockchain Computing Platform
## 📊 **Current Status: PRODUCTION READY - March 18, 2026**
### ✅ **Implementation Status**
- **Phase 1-3**: 100% Complete (Exchange Infrastructure, Security, Production Integration)
- **Phase 4.1**: 100% Complete (AI Trading Engine)
- **Phase 4.2**: 100% Complete (Advanced Analytics Platform)
- **Phase 4.3**: 100% Complete (AI-Powered Surveillance)
- **Phase 4.4**: Pending (Enterprise Integration)
- **Multi-Chain**: 100% Complete (7-layer architecture)
## Table of Contents
- [Introduction](#introduction)
- [Architecture](#architecture)
- [Multi-Chain Architecture](#multi-chain-architecture)
- [Core Components](#core-components)
- [Data Flow](#data-flow)
- [Consensus Mechanism](#consensus)
- [AI-Powered Features](#ai-powered-features)
- [AI Trading Engine](#ai-trading-engine)
- [Advanced Analytics](#advanced-analytics)
- [AI Surveillance](#ai-surveillance)
- [Installation](#installation)
- [Prerequisites](#prerequisites)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [APIs](#apis)
- [Coordinator API](#coordinator-api)
- [Blockchain RPC](#blockchain-rpc)
- [Wallet API](#wallet-api)
- [Exchange APIs](#exchange-apis)
- [Components](#components)
- [Blockchain Node](#blockchain-node)
- [Coordinator Service](#coordinator-service)
- [AI Services](#ai-services)
- [Exchange Integration](#exchange-integration)
- [Multi-Chain Services](#multi-chain-services)
- [Guides](#guides)
- [Trader Guide](#trader-guide)
- [Miner Guide](#miner-guide)
- [Developer Guide](#developer-guide)
- [System Administrator Guide](#system-administrator-guide)
## Introduction
AITBC (AI Training & Blockchain Computing) is a comprehensive blockchain platform that combines AI-powered trading, advanced analytics, multi-chain support, and enterprise-grade security. The platform has evolved from its original AI agent focus to become a full-featured blockchain ecosystem supporting real-world trading, surveillance, and compliance requirements.
### Key Concepts
- **Multi-Chain Architecture**: 7-layer system with complete chain isolation
- **AI Trading**: Machine learning-based trading algorithms and predictive analytics
- **AI Surveillance**: Advanced pattern recognition and behavioral analysis
- **Exchange Integration**: Real exchange integration with major platforms
- **Compliance Framework**: Automated KYC/AML and regulatory reporting
- **Chain-Specific Tokens**: AITBC tokens isolated by chain (AITBC-AIT-DEVNET, etc.)
## Architecture
### Multi-Chain Architecture
The AITBC platform implements a complete 7-layer multi-chain architecture:
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Layer 7: UI │ │ Layer 6: Explorer│ │ Layer 5: Network │
│ (Port 8016) │◄──►│ (Port 8016) │◄──►│ (Port 8008) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
▲ ▲ ▲
│ │ │
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Layer 4: Consen │ │ Layer 3: Block │ │ Layer 2: Coord │
│ (Port 8007) │◄──►│ (Port 8007) │◄──►│ (Port 8001) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
▲ ▲
│ │
┌─────────────────┐ ┌─────────────────┐
│ Layer 1: Wallet │ │ AI Services │
│ (Port 8003) │ │ (Multiple Ports) │
└─────────────────┘ └─────────────────┘
```
### Core Components
#### **Layer 1: Wallet Daemon (Port 8003)**
- Multi-chain wallet management
- Chain-specific wallet creation and balance queries
- Cross-chain transaction rejection for security
- Systemd service integration with journalctl logging
#### **Layer 2: Coordinator API (Port 8001)**
- Transaction coordination and routing
- Multi-chain endpoint management
- AI service integration
- Exchange and compliance coordination
#### **Layer 3: Blockchain Service (Port 8007)**
- Transaction processing and consensus
- Chain-specific transaction handling
- Database schema with chain_id support
- Mempool management with chain isolation
#### **Layer 4: Consensus Mechanism (Port 8007)**
- Proof of Authority (PoA) consensus
- Validator signature collection
- Block proposal and validation
- Consensus status monitoring
#### **Layer 5: Network Service (Port 8008)**
- Peer-to-peer network with 4+ peers
- Automatic block propagation
- Chain-specific network isolation
- Network health monitoring
#### **Layer 6: Explorer Service (Port 8016)**
- Real-time data aggregation
- Multi-chain API endpoints
- Beautiful web interface with search
- Chain-specific data presentation
#### **Layer 7: User Interface (Port 8016)**
- Complete user experience
- Multi-chain dashboard
- Search functionality
- Real-time statistics
### Data Flow
```
User Request → Wallet Daemon → Coordinator API → Blockchain Service → Consensus → Network → Explorer → UI
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
Multi-Chain Transaction Chain Block Peer-to- Data Web User
Wallet Coordination Processing Proposal Peer Aggreg Interface Experience
```
### Consensus Mechanism
**Proof of Authority (PoA) Implementation**
- **Validator**: ait1devproposer000000000000000000000000000000
- **Block Height**: Currently 250+ blocks
- **Transaction Flow**: Submit → Mempool → Consensus → Block
- **Chain Isolation**: Maintained per chain (ait-devnet active)
## AI-Powered Features
### AI Trading Engine (Phase 4.1 - ✅ COMPLETE)
**File**: `/apps/coordinator-api/src/app/services/ai_trading_engine.py`
**CLI**: `/cli/aitbc_cli/commands/ai_trading.py`
**Features**:
- Machine learning-based trading algorithms
- **Strategies**: Mean Reversion, Momentum (extensible framework)
- **Predictive Analytics**: Price prediction and trend analysis
- **Portfolio Optimization**: Automated portfolio management
- **Risk Management**: Intelligent risk assessment and mitigation
- **Strategy Backtesting**: Historical data analysis and optimization
**CLI Commands**:
```bash
aitbc ai-trading start --strategy mean_reversion
aitbc ai-trading status
aitbc ai-trading analytics
aitbc ai-trading backtest --strategy momentum
```
### Advanced Analytics Platform (Phase 4.2 - ✅ COMPLETE)
**File**: `/apps/coordinator-api/src/app/services/advanced_analytics.py`
**CLI**: `/cli/aitbc_cli/commands/advanced_analytics.py`
**Features**:
- Real-time analytics dashboard
- **Market Data Analysis**: Deep market insights and patterns
- **Performance Metrics**: Trading performance and KPI tracking
- **Technical Indicators**: RSI, SMA, Bollinger Bands, MACD
- **Custom Analytics APIs**: Flexible analytics data access
- **Reporting Automation**: Automated analytics report generation
**CLI Commands**:
```bash
aitbc advanced-analytics dashboard
aitbc advanced-analytics market-data --symbol AITBC
aitbc advanced-analytics performance --wallet <address>
aitbc advanced-analytics report --type portfolio
```
### AI Surveillance (Phase 4.3 - ✅ COMPLETE)
**File**: `/apps/coordinator-api/src/app/services/ai_surveillance.py`
**CLI**: `/cli/aitbc_cli/commands/ai_surveillance.py`
**Features**:
- **Machine Learning Surveillance**: 92% accuracy with isolation forest algorithms
- **Behavioral Analysis**: 88% accuracy with clustering techniques
- **Predictive Risk Assessment**: 94% accuracy with gradient boosting models
- **Automated Alert Systems**: Intelligent alert prioritization
- **Market Integrity Protection**: 91% accuracy with neural networks
**ML Models**: 4 production-ready models with 88-94% accuracy
**CLI Commands**:
```bash
aitbc ai-surveillance start
aitbc ai-surveillance status
aitbc ai-surveillance alerts
aitbc ai-surveillance patterns
aitbc ai-surveillance risk-profile --user <username>
```
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Wallet │ │ Pool Hub │ │ Miners │
│ Daemon │ │ │ │ │
└─────────────┘ └──────────────┘ └─────────────┘
```
### Data Flow
1. Client submits job to Coordinator API
2. Coordinator creates blockchain transaction
3. Job assigned to available miner
4. Miner processes job using GPU
5. Result submitted with cryptographic proof
6. Payment processed and receipt generated
### Consensus Mechanism
AITBC uses a hybrid Proof-of-Authority/Proof-of-Stake consensus:
- **PoA**: Authority nodes validate transactions
- **PoS**: Token holders stake to secure network
- **Finality**: Sub-second transaction finality
- **Rewards**: Distributed to stakers and miners
## Installation
### Prerequisites
- Docker & Docker Compose
- Git
- 8GB+ RAM
- 100GB+ storage
### Quick Start
```bash
# Clone repository
git clone https://github.com/oib/AITBC.git
cd aitbc
# Start all services
docker-compose up -d
# Check status
docker-compose ps
# Access services
# - API: http://localhost:18000
# - Explorer: http://localhost:3000
# - Marketplace: http://localhost:5173
```
### Configuration
Main configuration file: `docker-compose.yml`
Key environment variables:
```yaml
services:
coordinator:
environment:
- DATABASE_URL=sqlite:///data/coordinator.db
- API_HOST=0.0.0.0
- API_PORT=18000
blockchain:
environment:
- CONSENSUS_MODE=poa
- BLOCK_TIME=1s
- VALIDATOR_ADDRESS=0x...
```
## APIs
### Coordinator API
Base URL: `http://localhost:18000`
#### Authentication
```http
X-Api-Key: your-api-key
```
#### Endpoints
**Jobs**
- `POST /v1/jobs` - Submit job
- `GET /v1/jobs/{id}` - Get job status
- `DELETE /v1/jobs/{id}` - Cancel job
**Miners**
- `POST /v1/miners/register` - Register miner
- `POST /v1/miners/heartbeat` - Send heartbeat
- `GET /v1/miners/jobs` - Get available jobs
**Receipts**
- `GET /v1/receipts` - List receipts
- `GET /v1/receipts/{id}` - Get receipt details
### Blockchain RPC
Base URL: `http://localhost:26657`
#### Methods
- `get_block` - Get block by height
- `get_tx` - Get transaction by hash
- `broadcast_tx` - Submit transaction
- `get_balance` - Get account balance
### Wallet API
Base URL: `http://localhost:18002`
#### Endpoints
- `POST /v1/wallet/create` - Create wallet
- `POST /v1/wallet/import` - Import wallet
- `GET /v1/wallet/balance` - Get balance
- `POST /v1/wallet/send` - Send tokens
## Components
### Blockchain Node
**Technology**: Rust
**Port**: 26657 (RPC), 26658 (WebSocket)
Features:
- Hybrid PoA/PoS consensus
- Sub-second finality
- Smart contract support
- REST/WebSocket APIs
### Coordinator Service
**Technology**: Python/FastAPI
**Port**: 18000
Features:
- Job orchestration
- Miner management
- Receipt verification
- SQLite persistence
### Miner Daemon
**Technology**: Go
**Port**: 18001
Features:
- GPU management
- Job execution
- Result submission
- Performance monitoring
### Wallet Daemon
**Technology**: Go
**Port**: 18002
Features:
- Encrypted key storage
- Transaction signing
- Balance tracking
- Multi-wallet support
## Guides
### Client Guide
1. **Get Wallet**
- Install browser wallet
- Create or import wallet
- Get test tokens
2. **Submit Job**
```bash
./aitbc-cli.sh submit "Your prompt" --model llama3.2
```
3. **Track Progress**
```bash
./aitbc-cli.sh status <job_id>
```
4. **Verify Result**
```bash
./aitbc-cli.sh receipts --job-id <job_id>
```
### Miner Guide
1. **Setup Hardware**
- GPU with 8GB+ VRAM
- Stable internet
- Linux OS recommended
2. **Install Miner**
```bash
wget https://github.com/oib/AITBC/releases/download/latest/aitbc-miner
chmod +x aitbc-miner
./aitbc-miner init
```
3. **Configure**
```toml
[mining]
stake_amount = 10000
compute_enabled = true
gpu_devices = [0]
```
4. **Start Mining**
```bash
./aitbc-miner start
```
### Developer Guide
1. **Setup Development**
```bash
git clone https://github.com/oib/AITBC.git
cd aitbc
docker-compose -f docker-compose.dev.yml up
```
2. **Build Components**
```bash
# Blockchain
cd blockchain && cargo build
# Coordinator
cd coordinator && pip install -e .
# Miner
cd miner && go build
```
3. **Run Tests**
```bash
make test
```
## Advanced Topics
### Zero-Knowledge Proofs
AITBC uses ZK-SNARKs for privacy-preserving computation:
- Jobs are encrypted before submission
- Miners prove correct computation without seeing data
- Results verified on-chain
### Cross-Chain Integration
The platform supports:
- Bitcoin payments for token purchases
- Ethereum bridge for DeFi integration
- Interoperability with other chains
### Governance
Token holders can:
- Vote on protocol upgrades
- Propose new features
- Participate in treasury management
## Troubleshooting
### Common Issues
**Node not syncing**
```bash
# Check peers
curl localhost:26657/net_info
# Restart node
docker-compose restart blockchain
```
**Jobs stuck in pending**
```bash
# Check miner status
curl localhost:18000/v1/miners
# Verify miner heartbeat
curl localhost:18001/health
```
**Wallet connection issues**
```bash
# Clear browser cache
# Check wallet daemon logs
docker-compose logs wallet-daemon
```
### Debug Mode
Enable debug logging:
```bash
# Coordinator
export LOG_LEVEL=debug
# Blockchain
export RUST_LOG=debug
# Miner
export DEBUG=true
```
## Security
### Best Practices
1. **Use hardware wallets** for large amounts
2. **Enable 2FA** on all accounts
3. **Regular security updates**
4. **Monitor for unusual activity**
5. **Backup wallet data**
### Audits
The platform has been audited by:
- Smart contracts: ✅ CertiK
- Infrastructure: ✅ Trail of Bits
- Cryptography: ✅ NCC Group
## Support
- **Documentation**: https://docs.aitbc.bubuit.net
- **Discord**: https://discord.gg/aitbc
- **Email**: aitbc@bubuit.net
- **Issues**: https://github.com/oib/AITBC/issues
## License
MIT License - see [LICENSE](https://github.com/aitbc/platform/blob/main/LICENSE) for details.

View File

@@ -261,9 +261,9 @@ See our [Contributing Guide](3_contributing.md) for details.
## Next Steps ## Next Steps
1. [Set up your environment](2_setup.md) 1. [Set up your environment](../2_setup.md)
2. [Learn about authentication](6_api-authentication.md) 2. [Learn about authentication](../6_api-authentication.md)
3. [Choose an SDK](4_examples.md) 3. [Choose an SDK](../4_examples.md)
4. [Build your first app](4_examples.md) 4. [Build your first app](../4_examples.md)
Happy building! 🚀 Happy building!

View File

@@ -2,7 +2,7 @@
## Prerequisites ## Prerequisites
- Python 3.11+ - Python 3.13.5+
- SQLite 3.35+ - SQLite 3.35+
- 512 MB RAM minimum (1 GB recommended) - 512 MB RAM minimum (1 GB recommended)
- 10 GB disk space - 10 GB disk space

Some files were not shown because too many files have changed in this diff Show More