Compare commits

...

23 Commits

Author SHA1 Message Date
e1184bcc13 resolve merge conflicts in .gitignore and .env.example
Some checks failed
AITBC CI/CD Pipeline / lint-and-test (3.11) (pull_request) Has been cancelled
AITBC CI/CD Pipeline / lint-and-test (3.12) (pull_request) Has been cancelled
AITBC CI/CD Pipeline / lint-and-test (3.13) (pull_request) Has been cancelled
AITBC CLI Level 1 Commands Test / test-cli-level1 (3.11) (pull_request) Has been cancelled
AITBC CLI Level 1 Commands Test / test-cli-level1 (3.12) (pull_request) Has been cancelled
AITBC CLI Level 1 Commands Test / test-cli-level1 (3.13) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (apps/coordinator-api/src) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (cli/aitbc_cli) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-core/src) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-crypto/src) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-sdk/src) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (tests) (pull_request) Has been cancelled
Security Scanning / CodeQL Security Analysis (javascript) (pull_request) Has been cancelled
Security Scanning / CodeQL Security Analysis (python) (pull_request) Has been cancelled
Security Scanning / Dependency Security Scan (pull_request) Has been cancelled
Security Scanning / Container Security Scan (pull_request) Has been cancelled
Security Scanning / OSSF Scorecard (pull_request) Has been cancelled
AITBC CI/CD Pipeline / test-cli (pull_request) Has been cancelled
AITBC CI/CD Pipeline / test-services (pull_request) Has been cancelled
AITBC CI/CD Pipeline / test-production-services (pull_request) Has been cancelled
AITBC CI/CD Pipeline / security-scan (pull_request) Has been cancelled
AITBC CI/CD Pipeline / build (pull_request) Has been cancelled
AITBC CI/CD Pipeline / deploy-staging (pull_request) Has been cancelled
AITBC CI/CD Pipeline / deploy-production (pull_request) Has been cancelled
AITBC CI/CD Pipeline / performance-test (pull_request) Has been cancelled
AITBC CI/CD Pipeline / docs (pull_request) Has been cancelled
AITBC CI/CD Pipeline / release (pull_request) Has been cancelled
AITBC CI/CD Pipeline / notify (pull_request) Has been cancelled
AITBC CLI Level 1 Commands Test / test-summary (pull_request) Has been cancelled
Security Scanning / Security Summary Report (pull_request) Has been cancelled
2026-03-23 09:25:51 +01:00
d024f6e6f3 fix: update gitignore for gitea token file
- Add .gitea-token to ignored files
- Fix duplicate comment in Secrets & Credentials section
2026-03-20 12:50:54 +01:00
7cdd8f1fd0 Merge aitbc1/blockchain-production into main: Enhanced chain sync, PoA transaction processing, and production genesis tooling
Some checks failed
AITBC CI/CD Pipeline / lint-and-test (3.11) (pull_request) Has been cancelled
AITBC CI/CD Pipeline / lint-and-test (3.12) (pull_request) Has been cancelled
AITBC CI/CD Pipeline / lint-and-test (3.13) (pull_request) Has been cancelled
AITBC CLI Level 1 Commands Test / test-cli-level1 (3.11) (pull_request) Has been cancelled
AITBC CLI Level 1 Commands Test / test-cli-level1 (3.12) (pull_request) Has been cancelled
AITBC CLI Level 1 Commands Test / test-cli-level1 (3.13) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (apps/coordinator-api/src) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (cli/aitbc_cli) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-core/src) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-crypto/src) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-sdk/src) (pull_request) Has been cancelled
Security Scanning / Bandit Security Scan (tests) (pull_request) Has been cancelled
Security Scanning / CodeQL Security Analysis (javascript) (pull_request) Has been cancelled
Security Scanning / CodeQL Security Analysis (python) (pull_request) Has been cancelled
Security Scanning / Dependency Security Scan (pull_request) Has been cancelled
Security Scanning / Container Security Scan (pull_request) Has been cancelled
Security Scanning / OSSF Scorecard (pull_request) Has been cancelled
AITBC CI/CD Pipeline / test-cli (pull_request) Has been cancelled
AITBC CI/CD Pipeline / test-services (pull_request) Has been cancelled
AITBC CI/CD Pipeline / test-production-services (pull_request) Has been cancelled
AITBC CI/CD Pipeline / security-scan (pull_request) Has been cancelled
AITBC CI/CD Pipeline / build (pull_request) Has been cancelled
AITBC CI/CD Pipeline / deploy-staging (pull_request) Has been cancelled
AITBC CI/CD Pipeline / deploy-production (pull_request) Has been cancelled
AITBC CI/CD Pipeline / performance-test (pull_request) Has been cancelled
AITBC CI/CD Pipeline / docs (pull_request) Has been cancelled
AITBC CI/CD Pipeline / release (pull_request) Has been cancelled
AITBC CI/CD Pipeline / notify (pull_request) Has been cancelled
AITBC CLI Level 1 Commands Test / test-summary (pull_request) Has been cancelled
Security Scanning / Security Summary Report (pull_request) Has been cancelled
2026-03-20 10:50:43 +01:00
fb3ac34ed3 Fix poetry lock file and update mypy dependency version 2026-03-20 10:37:52 +01:00
096ce30728 Add logging for mempool drain in PoA proposer 2026-03-20 10:37:52 +01:00
74ab1657f7 refactor: consolidate environment configuration and add production genesis tooling
- Replace verbose .env.example with concise production-ready template
- Add blockchain core, coordinator API, and marketplace web sections
- Remove development/production split in favor of single config file
- Add create-keystore command to genesis CLI for encrypted key generation
- Add init-production command to initialize production chain DB from genesis
- Add create_keystore helper function in scripts/keystore.py
-
2026-03-20 09:39:52 +01:00
eef496b70a feat(chain_sync): apply transaction state changes during block import
- Import Account model for balance and nonce updates
- Upsert sender and recipient accounts during transaction import
- Apply balance changes (sender -= value + fee, recipient += value)
- Update sender nonce based on transaction nonce or increment
- Assume block validity already verified on producer node
- Extract transaction data from payload for state updates
2026-03-19 17:17:33 +01:00
845c648313 feat(chain_sync): add configurable source/import hosts and improve rate limit handling
- Add source_host/source_port parameters for flexible block polling configuration
- Add import_host/import_port parameters to separate import target from source
- Bypass rate limiting for localhost traffic (127.0.0.1, ::1) in middleware
- Increase rate limit from 200 to 5000 requests per 60s for RPC throughput
- Add receiver ready event to prevent dropping initial block broadcasts
- Add special handling for 429 rate
2026-03-19 16:08:48 +01:00
0c85f89776 feat(chain_sync): add retry logic with exponential backoff for RPC connections and block imports
- Add retry mechanism with exponential backoff for block broadcast loop
- Implement max 5 retries with 2s base delay for RPC connection failures
- Reset retry count on successful connection
- Add 20s wait period after max retries before resetting counter
- Add retry logic for block import with 3 attempts and 1s base delay
- Handle non-200 HTTP responses as exceptions to trigger retries
- Improve error logging
2026-03-19 15:01:28 +01:00
0218cd1422 feat(chain_sync): add leader host routing for follower nodes
- Add leader_host parameter to ChainSyncService for follower node configuration
- Route block imports to leader node when running as follower
- Add --leader-host CLI argument for follower node setup
- Update get_token_supply to calculate actual values from database
- Replace hardcoded supply values with real account balances and counts
- Calculate circulating supply from actual account balances
- Use total_accounts from database query
2026-03-19 13:50:49 +01:00
f2849ee4a9 feat(consensus): implement transaction processing in PoA block proposer
- Process transactions from mempool during block proposal
- Update sender and recipient account balances
- Create transaction records with confirmed status
- Include transaction hashes in block hash computation
- Update tx_count in blocks based on processed transactions
- Add balance validation and nonce management
- Handle transaction failures gracefully with logging
- Fix get_balance endpoint to use chain_id helper
- Update
2026-03-19 13:25:29 +01:00
b4b5a57390 refactor: clean up configuration and add production infrastructure
- Add .aitbc.yaml configuration file with test values
- Simplify .gitignore by removing merge conflicts and redundant entries
- Reorganize .gitignore sections for better clarity
- Set chain_id and proposer_id to empty strings in config.py (require explicit configuration)
- Add production Helm values configuration
- Add production nginx configuration
- Update environment variable handling in chain settings
2026-03-19 13:01:21 +01:00
5f2ab48b9a Shared Chain Implementation 2026-03-19 13:01:21 +01:00
e791aa13da refactor: clean up configuration and add production infrastructure
- Add .aitbc.yaml configuration file with test values
- Simplify .gitignore by removing merge conflicts and redundant entries
- Reorganize .gitignore sections for better clarity
- Set chain_id and proposer_id to empty strings in config.py (require explicit configuration)
- Add production Helm values configuration
- Add production nginx configuration
- Update environment variable handling in chain settings
2026-03-19 12:59:34 +01:00
978d4d22f6 Shared Chain Implementation 2026-03-19 12:49:08 +01:00
1205a7c681 fix(dev_heartbeat): use correct sh() signature, fix CLI syntax path 2026-03-19 12:31:25 +01:00
97d989bc04 refactor(blockchain): use settings.chain_id as default instead of hardcoded "ait-devnet"
- Replace hardcoded "ait-devnet" defaults with settings.chain_id throughout codebase
- Add get_chain_id() helper function in RPC router
- Update mempool methods to use settings.chain_id when chain_id is None
- Update blockchain node main to use settings.chain_id for gossip handlers
- Update RPC endpoints to accept None and default to settings.chain_id
- Update token supply endpoint to handle mainnet vs devnet (
2026-03-19 12:31:19 +01:00
6020ad04c4 refactor(blockchain): use settings.chain_id as default instead of hardcoded "ait-devnet"
- Replace hardcoded "ait-devnet" defaults with settings.chain_id throughout codebase
- Add get_chain_id() helper function in RPC router
- Update mempool methods to use settings.chain_id when chain_id is None
- Update blockchain node main to use settings.chain_id for gossip handlers
- Update RPC endpoints to accept None and default to settings.chain_id
- Update token supply endpoint to handle mainnet vs devnet (
2026-03-19 12:29:24 +01:00
d99bb73a9b refactor(combined_main): remove P2P placeholder and improve shutdown handling
- Remove P2P placeholder server integration
- Add global service instance for signal handlers
- Add set_stop_event method for clean shutdown
- Improve signal handler to properly trigger stop event
- Store event loop reference for shutdown coordination
- Update logging to reflect P2P removal
2026-03-19 12:19:17 +01:00
4b78f3707b P2P functionality has been successfully merged into the main blockchain node service 2026-03-19 10:56:35 +00:00
4c2062289c fix(dev_heartbeat): use correct sh() signature, fix CLI syntax path 2026-03-19 10:31:06 +00:00
ffbf0b8966 Merge branch 'main' of gitea.bubuit.net:oib/aitbc 2026-03-19 10:17:18 +00:00
92f3d84815 Merge branch 'aitbc/36-remove-faucet-from-prod-genesis'
no need for faucet
2026-03-18 15:38:43 +00:00
130 changed files with 15681 additions and 557 deletions

2
.aitbc.yaml Normal file
View File

@@ -0,0 +1,2 @@
api_key: test_value
coordinator_url: http://127.0.0.1:18000

View File

@@ -3,57 +3,56 @@
# Run: python config/security/environment-audit.py --format text
# =========================
# Blockchain core (example values)
# Blockchain core
# =========================
chain_id=ait-devnet
supported_chains=ait-devnet
rpc_bind_host=127.0.0.1
chain_id=ait-mainnet
supported_chains=ait-mainnet
rpc_bind_host=0.0.0.0
rpc_bind_port=8006
p2p_bind_host=127.0.0.2
p2p_bind_host=0.0.0.0
p2p_bind_port=8005
proposer_id=ait-devnet-proposer
proposer_key=
keystore_path=./keystore
keystore_password_file=./keystore/.password
gossip_backend=memory
gossip_broadcast_url=
db_path=./data/chain.db
proposer_id=aitbc1genesis
proposer_key=changeme_hex_private_key
keystore_path=/opt/aitbc/keystore
keystore_password_file=/opt/aitbc/keystore/.password
gossip_backend=broadcast
gossip_broadcast_url=redis://127.0.0.1:6379
db_path=/opt/aitbc/apps/blockchain-node/data/ait-mainnet/chain.db
mint_per_unit=0
coordinator_ratio=0.05
block_time_seconds=2
enable_block_production=false
block_time_seconds=60
enable_block_production=true
# =========================
# Coordinator API (example values)
# Coordinator API
# =========================
APP_ENV=development
APP_ENV=production
APP_HOST=127.0.0.1
APP_PORT=8011
DATABASE__URL=sqlite:////opt/aitbc/data/coordinator/coordinator.db
BLOCKCHAIN_RPC_URL=http://127.0.0.1:8006
ALLOW_ORIGINS=["http://localhost:8011","http://localhost:8000"]
DATABASE__URL=sqlite:///./data/coordinator.db
BLOCKCHAIN_RPC_URL=http://127.0.0.1:8026
ALLOW_ORIGINS=["http://localhost:8011","http://localhost:8000","http://8026"]
JOB_TTL_SECONDS=900
HEARTBEAT_INTERVAL_SECONDS=10
HEARTBEAT_TIMEOUT_SECONDS=30
RATE_LIMIT_REQUESTS=60
RATE_LIMIT_WINDOW_SECONDS=60
CLIENT_API_KEYS=["client_dev_key"]
MINER_API_KEYS=["miner_dev_key"]
ADMIN_API_KEYS=["admin_dev_key"]
CLIENT_API_KEYS=["client_prod_key_use_real_value"]
MINER_API_KEYS=["miner_prod_key_use_real_value"]
ADMIN_API_KEYS=["admin_prod_key_use_real_value"]
HMAC_SECRET=change_this_to_a_32_byte_random_secret
JWT_SECRET=change_this_to_another_32_byte_random_secret
# =========================
# Marketplace Web (example values)
# Marketplace Web
# =========================
VITE_MARKETPLACE_DATA_MODE=mock
VITE_MARKETPLACE_DATA_MODE=live
VITE_MARKETPLACE_API=/api
VITE_MARKETPLACE_ENABLE_BIDS=false
VITE_MARKETPLACE_ENABLE_BIDS=true
VITE_MARKETPLACE_REQUIRE_AUTH=false
# =========================
# Notes
# =========================
# For production: copy this to .env and replace with real values/secrets
# Move secrets to a secrets manager and reference via secretRef
# For production: move secrets to a secrets manager and reference via secretRef
# Validate config: python config/security/environment-audit.py --format text

347
.gitignore vendored
View File

@@ -1,7 +1,4 @@
<<<<<<< Updated upstream
# AITBC Monorepo ignore rules
# Updated: 2026-03-03 - Project organization workflow completed
# Development files organized into dev/ subdirectories
# ===================
# Python
@@ -26,7 +23,9 @@ htmlcov/
.mypy_cache/
.ruff_cache/
# Environment files
# ===================
# Environment Files (SECRETS - NEVER COMMIT)
# ===================
*.env
.env.*
!.env.example
@@ -34,90 +33,45 @@ htmlcov/
.env.*.local
# ===================
# Development Environment (organized)
# ===================
dev/env/.venv/
dev/env/node_modules/
dev/env/cli_env/
dev/cache/.pytest_cache/
dev/cache/.ruff_cache/
dev/cache/.vscode/
dev/cache/logs/
dev/scripts/__pycache__/
dev/scripts/*.pyc
dev/scripts/*.pyo
# ===================
# Databases
# Database & Data
# ===================
*.db
*.sqlite
*.sqlite3
*/data/*.db
*.db-wal
*.db-shm
data/
# Alembic
alembic.ini
migrations/versions/__pycache__/
apps/blockchain-node/data/
# ===================
# Node / JavaScript
# Logs & Runtime
# ===================
node_modules/
dist/
build/
.npm/
.pnpm/
yarn.lock
pnpm-lock.yaml
.next/
.nuxt/
.cache/
# ===================
# Development Tests (organized)
# ===================
dev/tests/__pycache__/
dev/tests/*.pyc
dev/tests/test_results/
dev/tests/simple_test_results.json
dev/tests/data/
dev/tests/*.db
dev/multi-chain/__pycache__/
dev/multi-chain/*.pyc
dev/multi-chain/test_results/
# ===================
# Logs & Runtime (organized)
# ===================
logs/
dev/cache/logs/
*.log
*.log.*
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pids/
logs/
*.pid
*.seed
# ===================
# Editor & IDE
# Secrets & Credentials
# ===================
*.pem
*.key
*.crt
*.p12
secrets/
credentials/
.secrets
.gitea_token.sh
keystore/
# ===================
# IDE & Editor
# ===================
.idea/
.vscode/
.idea/
*.swp
*.swo
*~
.project
.classpath
.settings/
# ===================
# Runtime / PID files
# ===================
*.pid
apps/.service_pids
# ===================
# OS Files
@@ -132,25 +86,22 @@ Desktop.ini
# ===================
# Build & Compiled
# ===================
build/
dist/
target/
*.o
*.a
*.lib
*.dll
*.dylib
target/
out/
# ===================
# Secrets & Credentials
# Node.js
# ===================
*.pem
*.key
*.crt
*.p12
secrets/
credentials/
.secrets
.gitea_token.sh
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# ===================
# Backup Files (organized)
@@ -180,86 +131,11 @@ backup/README.md
# ===================
tmp/
temp/
=======
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Virtual environments
venv/
env/
ENV/
.venv/
.env/
# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Logs
*.log
logs/
# Database
*.db
*.sqlite
*.sqlite3
*.db-wal
*.db-shm
# Configuration with secrets
.env
.env.local
.env.*.local
config.json
secrets.json
# Temporary files
*.tmp
*.temp
*.bak
*.backup
# ===================
# Environment Files
# ===================
.env
.env.local
.env.production
*.env
.env.*.local
# ===================
# Windsurf IDE
# ===================
@@ -267,165 +143,16 @@ secrets.json
.snapshots/
# ===================
# Test Results & Artifacts
# ===================
test-results/
**/test-results/
# ===================
# Development Logs - Keep in dev/logs/
# ===================
*.log
*.out
*.err
wget-log
download.log
# ===================
# Wallet files (contain keys/balances)
# Wallet Files (contain private keys)
# ===================
*.json
home/client/client_wallet.json
home/genesis_wallet.json
home/miner/miner_wallet.json
# Root-level wallet backups (contain private keys)
*.json
# ===================
# Stale source copies
# Test Results
# ===================
src/aitbc_chain/
test-results/
**/test-results/
# ===================
# Project Specific
# ===================
# Coordinator database
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
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
data/
logs/
*.db
*.sqlite
wallet*.json
keystore/
certificates/
>>>>>>> Stashed changes
.gitea_token.sh

View File

@@ -32,6 +32,9 @@ class RateLimitMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
client_ip = request.client.host if request.client else "unknown"
# Bypass rate limiting for localhost (sync/health internal traffic)
if client_ip in {"127.0.0.1", "::1"}:
return await call_next(request)
now = time.time()
# Clean old entries
self._requests[client_ip] = [
@@ -109,7 +112,8 @@ def create_app() -> FastAPI:
# Middleware (applied in reverse order)
app.add_middleware(RequestLoggingMiddleware)
app.add_middleware(RateLimitMiddleware, max_requests=200, window_seconds=60)
# Allow higher RPC throughput (sync + node traffic)
app.add_middleware(RateLimitMiddleware, max_requests=5000, window_seconds=60)
app.add_middleware(
CORSMiddleware,
allow_origins=[

View File

@@ -0,0 +1,272 @@
#!/usr/bin/env python3
"""
Chain Synchronization Service
Keeps blockchain nodes synchronized by sharing blocks via P2P and Redis gossip
"""
import asyncio
import json
import logging
import time
from typing import Dict, Any, Optional, List
logger = logging.getLogger(__name__)
class ChainSyncService:
def __init__(self, redis_url: str, node_id: str, rpc_port: int = 8006, leader_host: str = None,
source_host: str = "127.0.0.1", source_port: int = None,
import_host: str = "127.0.0.1", import_port: int = None):
self.redis_url = redis_url
self.node_id = node_id
self.rpc_port = rpc_port # kept for backward compat (local poll if source_port None)
self.leader_host = leader_host # Host of the leader node (legacy)
self.source_host = source_host
self.source_port = source_port or rpc_port
self.import_host = import_host
self.import_port = import_port or rpc_port
self._stop_event = asyncio.Event()
self._redis = None
self._receiver_ready = asyncio.Event()
async def start(self):
"""Start chain synchronization service"""
logger.info(f"Starting chain sync service for node {self.node_id}")
try:
import redis.asyncio as redis
self._redis = redis.from_url(self.redis_url)
await self._redis.ping()
logger.info("Connected to Redis for chain sync")
except Exception as e:
logger.error(f"Failed to connect to Redis: {e}")
return
# Start block broadcasting task
# Start block receiving task
receive_task = asyncio.create_task(self._receive_blocks())
# Wait until receiver subscribed so we don't drop the initial burst
await self._receiver_ready.wait()
broadcast_task = asyncio.create_task(self._broadcast_blocks())
try:
await self._stop_event.wait()
finally:
broadcast_task.cancel()
receive_task.cancel()
await asyncio.gather(broadcast_task, receive_task, return_exceptions=True)
if self._redis:
await self._redis.close()
async def stop(self):
"""Stop chain synchronization service"""
logger.info("Stopping chain sync service")
self._stop_event.set()
async def _broadcast_blocks(self):
"""Broadcast local blocks to other nodes"""
import aiohttp
last_broadcast_height = 0
retry_count = 0
max_retries = 5
base_delay = 2
while not self._stop_event.is_set():
try:
# Get current head from local RPC
async with aiohttp.ClientSession() as session:
async with session.get(f"http://{self.source_host}:{self.source_port}/rpc/head") as resp:
if resp.status == 200:
head_data = await resp.json()
current_height = head_data.get('height', 0)
# Reset retry count on successful connection
retry_count = 0
# Broadcast new blocks
if current_height > last_broadcast_height:
for height in range(last_broadcast_height + 1, current_height + 1):
block_data = await self._get_block_by_height(height, session)
if block_data:
await self._broadcast_block(block_data)
last_broadcast_height = current_height
logger.info(f"Broadcasted blocks up to height {current_height}")
elif resp.status == 429:
raise Exception("rate_limit")
else:
raise Exception(f"RPC returned status {resp.status}")
except Exception as e:
retry_count += 1
# If rate-limited, wait longer before retrying
if str(e) == "rate_limit":
delay = base_delay * 30
logger.warning(f"RPC rate limited, retrying in {delay}s")
await asyncio.sleep(delay)
continue
if retry_count <= max_retries:
delay = base_delay * (2 ** (retry_count - 1)) # Exponential backoff
logger.warning(f"RPC connection failed (attempt {retry_count}/{max_retries}), retrying in {delay}s: {e}")
await asyncio.sleep(delay)
continue
else:
logger.error(f"RPC connection failed after {max_retries} attempts, waiting {base_delay * 10}s: {e}")
await asyncio.sleep(base_delay * 10)
retry_count = 0 # Reset retry count after long wait
await asyncio.sleep(base_delay) # Check every 2 seconds when connected
async def _receive_blocks(self):
"""Receive blocks from other nodes via Redis"""
if not self._redis:
return
pubsub = self._redis.pubsub()
await pubsub.subscribe("blocks")
self._receiver_ready.set()
logger.info("Subscribed to block broadcasts")
async for message in pubsub.listen():
if self._stop_event.is_set():
break
if message['type'] == 'message':
try:
block_data = json.loads(message['data'])
await self._import_block(block_data)
except Exception as e:
logger.error(f"Error processing received block: {e}")
async def _get_block_by_height(self, height: int, session) -> Optional[Dict[str, Any]]:
"""Get block data by height from local RPC"""
try:
async with session.get(f"http://{self.source_host}:{self.source_port}/rpc/blocks-range?start={height}&end={height}") as resp:
if resp.status == 200:
blocks_data = await resp.json()
blocks = blocks_data.get('blocks', [])
block = blocks[0] if blocks else None
return block
except Exception as e:
logger.error(f"Error getting block {height}: {e}")
return None
async def _broadcast_block(self, block_data: Dict[str, Any]):
"""Broadcast block to other nodes via Redis"""
if not self._redis:
return
try:
await self._redis.publish("blocks", json.dumps(block_data))
logger.debug(f"Broadcasted block {block_data.get('height')}")
except Exception as e:
logger.error(f"Error broadcasting block: {e}")
async def _import_block(self, block_data: Dict[str, Any]):
"""Import block from another node"""
import aiohttp
try:
# Don't import our own blocks
if block_data.get('proposer') == self.node_id:
return
# Determine target host - if we're a follower, import to leader, else import locally
target_host = self.import_host
target_port = self.import_port
# Retry logic for import
max_retries = 3
base_delay = 1
for attempt in range(max_retries):
try:
async with aiohttp.ClientSession() as session:
async with session.post(
f"http://{target_host}:{target_port}/rpc/importBlock",
json=block_data
) as resp:
if resp.status == 200:
result = await resp.json()
if result.get('accepted'):
logger.info(f"Imported block {block_data.get('height')} from {block_data.get('proposer')}")
else:
logger.debug(f"Rejected block {block_data.get('height')}: {result.get('reason')}")
return
else:
try:
body = await resp.text()
except Exception:
body = "<no body>"
raise Exception(f"HTTP {resp.status}: {body}")
except Exception as e:
if attempt < max_retries - 1:
delay = base_delay * (2 ** attempt)
logger.warning(f"Import failed (attempt {attempt + 1}/{max_retries}), retrying in {delay}s: {e}")
await asyncio.sleep(delay)
else:
logger.error(f"Failed to import block {block_data.get('height')} after {max_retries} attempts: {e}")
return
except Exception as e:
logger.error(f"Error importing block: {e}")
async def run_chain_sync(
redis_url: str,
node_id: str,
rpc_port: int = 8006,
leader_host: str = None,
source_host: str = "127.0.0.1",
source_port: int = None,
import_host: str = "127.0.0.1",
import_port: int = None,
):
"""Run chain synchronization service"""
service = ChainSyncService(
redis_url=redis_url,
node_id=node_id,
rpc_port=rpc_port,
leader_host=leader_host,
source_host=source_host,
source_port=source_port,
import_host=import_host,
import_port=import_port,
)
await service.start()
def main():
import argparse
parser = argparse.ArgumentParser(description="AITBC Chain Synchronization Service")
parser.add_argument("--redis", default="redis://localhost:6379", help="Redis URL")
parser.add_argument("--node-id", required=True, help="Node identifier")
parser.add_argument("--rpc-port", type=int, default=8006, help="RPC port")
parser.add_argument("--leader-host", help="Leader node host (for followers)")
parser.add_argument("--source-host", default="127.0.0.1", help="Host to poll for head/blocks")
parser.add_argument("--source-port", type=int, help="Port to poll for head/blocks")
parser.add_argument("--import-host", default="127.0.0.1", help="Host to import blocks into")
parser.add_argument("--import-port", type=int, help="Port to import blocks into")
args = parser.parse_args()
logging.basicConfig(level=logging.INFO)
try:
asyncio.run(run_chain_sync(
args.redis,
args.node_id,
args.rpc_port,
args.leader_host,
args.source_host,
args.source_port,
args.import_host,
args.import_port,
))
except KeyboardInterrupt:
logger.info("Chain sync service stopped by user")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python3
"""
Combined blockchain node and P2P service launcher
Runs both the main blockchain node and P2P placeholder service
"""
import asyncio
import logging
import os
import signal
import sys
from pathlib import Path
# Add src to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from aitbc_chain.main import BlockchainNode, _run as run_node
from aitbc_chain.config import settings
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class CombinedService:
def __init__(self):
self._stop_event = asyncio.Event()
self._tasks = []
self._loop = None
def set_stop_event(self):
"""Set the stop event to trigger shutdown"""
if self._stop_event and not self._stop_event.is_set():
self._stop_event.set()
async def start(self):
"""Start both blockchain node and P2P server"""
self._loop = asyncio.get_running_loop()
logger.info("Starting combined blockchain service")
# Start blockchain node in background
node_task = asyncio.create_task(run_node())
self._tasks.append(node_task)
logger.info(f"Combined service started - Node on mainnet")
try:
await self._stop_event.wait()
finally:
await self.stop()
async def stop(self):
"""Stop all services"""
logger.info("Stopping combined blockchain service")
# Cancel all tasks
for task in self._tasks:
task.cancel()
# Wait for tasks to complete
if self._tasks:
await asyncio.gather(*self._tasks, return_exceptions=True)
self._tasks.clear()
logger.info("Combined service stopped")
# Global service instance for signal handler
_service_instance = None
def signal_handler(signum, frame):
"""Handle shutdown signals"""
logger.info(f"Received signal {signum}, initiating shutdown")
global _service_instance
if _service_instance:
_service_instance.set_stop_event()
async def main():
"""Main entry point"""
global _service_instance
service = CombinedService()
_service_instance = service
# Set up signal handlers
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
try:
await service.start()
except KeyboardInterrupt:
logger.info("Received keyboard interrupt")
finally:
await service.stop()
_service_instance = None
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -18,7 +18,7 @@ class ProposerConfig(BaseModel):
class ChainSettings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", case_sensitive=False)
chain_id: str = "ait-devnet"
chain_id: str = ""
supported_chains: str = "ait-devnet" # Comma-separated list of supported chain IDs
db_path: Path = Path("./data/chain.db")
@@ -28,7 +28,7 @@ class ChainSettings(BaseSettings):
p2p_bind_host: str = "127.0.0.2"
p2p_bind_port: int = 7070
proposer_id: str = "ait-devnet-proposer"
proposer_id: str = ""
proposer_key: Optional[str] = None
mint_per_unit: int = 0 # No new minting after genesis for production
@@ -36,6 +36,9 @@ class ChainSettings(BaseSettings):
block_time_seconds: int = 2
# Block production toggle (set false on followers)
enable_block_production: bool = True
# Block production limits
max_block_size_bytes: int = 1_000_000 # 1 MB
max_txs_per_block: int = 500

View File

@@ -120,11 +120,11 @@ class PoAProposer:
return
async def _propose_block(self) -> None:
# Check internal mempool
# Check internal mempool and include transactions
from ..mempool import get_mempool
if get_mempool().size(self._config.chain_id) == 0:
return
from ..models import Transaction, Account
mempool = get_mempool()
with self._session_factory() as session:
head = session.exec(select(Block).where(Block.chain_id == self._config.chain_id).order_by(Block.height.desc()).limit(1)).first()
next_height = 0
@@ -136,7 +136,71 @@ class PoAProposer:
interval_seconds = (datetime.utcnow() - head.timestamp).total_seconds()
timestamp = datetime.utcnow()
block_hash = self._compute_block_hash(next_height, parent_hash, timestamp)
# Pull transactions from mempool
max_txs = self._config.max_txs_per_block
max_bytes = self._config.max_block_size_bytes
pending_txs = mempool.drain(max_txs, max_bytes, self._config.chain_id)
self._logger.info(f"[PROPOSE] drained {len(pending_txs)} txs from mempool, chain={self._config.chain_id}")
# Process transactions and update balances
processed_txs = []
for tx in pending_txs:
try:
# Parse transaction data
tx_data = tx.content
sender = tx_data.get("sender")
recipient = tx_data.get("payload", {}).get("to")
value = tx_data.get("payload", {}).get("value", 0)
fee = tx_data.get("fee", 0)
if not sender or not recipient:
continue
# Get sender account
sender_account = session.get(Account, (self._config.chain_id, sender))
if not sender_account:
continue
# Check sufficient balance
total_cost = value + fee
if sender_account.balance < total_cost:
continue
# Get or create recipient account
recipient_account = session.get(Account, (self._config.chain_id, recipient))
if not recipient_account:
recipient_account = Account(chain_id=self._config.chain_id, address=recipient, balance=0, nonce=0)
session.add(recipient_account)
session.flush()
# Update balances
sender_account.balance -= total_cost
sender_account.nonce += 1
recipient_account.balance += value
# Create transaction record
transaction = Transaction(
chain_id=self._config.chain_id,
tx_hash=tx.tx_hash,
sender=sender,
recipient=recipient,
value=value,
fee=fee,
nonce=sender_account.nonce - 1,
timestamp=timestamp,
block_height=next_height,
status="confirmed"
)
session.add(transaction)
processed_txs.append(tx)
except Exception as e:
self._logger.warning(f"Failed to process transaction {tx.tx_hash}: {e}")
continue
# Compute block hash with transaction data
block_hash = self._compute_block_hash(next_height, parent_hash, timestamp, processed_txs)
block = Block(
chain_id=self._config.chain_id,
@@ -145,7 +209,7 @@ class PoAProposer:
parent_hash=parent_hash,
proposer=self._config.proposer_id,
timestamp=timestamp,
tx_count=0,
tx_count=len(processed_txs),
state_root=None,
)
session.add(block)
@@ -258,6 +322,11 @@ class PoAProposer:
with self._session_factory() as session:
return session.exec(select(Block).order_by(Block.height.desc()).limit(1)).first()
def _compute_block_hash(self, height: int, parent_hash: str, timestamp: datetime) -> str:
payload = f"{self._config.chain_id}|{height}|{parent_hash}|{timestamp.isoformat()}".encode()
def _compute_block_hash(self, height: int, parent_hash: str, timestamp: datetime, transactions: list = None) -> str:
# Include transaction hashes in block hash computation
tx_hashes = []
if transactions:
tx_hashes = [tx.tx_hash for tx in transactions]
payload = f"{self._config.chain_id}|{height}|{parent_hash}|{timestamp.isoformat()}|{'|'.join(sorted(tx_hashes))}".encode()
return "0x" + hashlib.sha256(payload).hexdigest()

View File

@@ -103,7 +103,7 @@ class BlockchainNode:
if isinstance(tx_data, str):
import json
tx_data = json.loads(tx_data)
chain_id = tx_data.get("chain_id", "ait-devnet")
chain_id = tx_data.get("chain_id", settings.chain_id)
mempool.add(tx_data, chain_id=chain_id)
except Exception as exc:
logger.error(f"Error processing transaction from gossip: {exc}")
@@ -121,7 +121,7 @@ class BlockchainNode:
if isinstance(block_data, str):
import json
block_data = json.loads(block_data)
chain_id = block_data.get("chain_id", "ait-devnet")
chain_id = block_data.get("chain_id", settings.chain_id)
logger.info(f"Importing block for chain {chain_id}: {block_data.get('height')}")
sync = ChainSync(session_factory=session_scope, chain_id=chain_id)
res = sync.import_block(block_data)
@@ -148,7 +148,11 @@ class BlockchainNode:
max_size=settings.mempool_max_size,
min_fee=settings.min_fee,
)
self._start_proposers()
# Start proposers only if enabled (followers set enable_block_production=False)
if getattr(settings, "enable_block_production", True):
self._start_proposers()
else:
logger.info("Block production disabled on this node", extra={"proposer_id": settings.proposer_id})
await self._setup_gossip_subscribers()
try:
await self._stop_event.wait()

View File

@@ -38,7 +38,10 @@ class InMemoryMempool:
self._max_size = max_size
self._min_fee = min_fee
def add(self, tx: Dict[str, Any], chain_id: str = "ait-devnet") -> str:
def add(self, tx: Dict[str, Any], chain_id: str = None) -> str:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
fee = tx.get("fee", 0)
if fee < self._min_fee:
raise ValueError(f"Fee {fee} below minimum {self._min_fee}")
@@ -59,11 +62,17 @@ class InMemoryMempool:
metrics_registry.increment(f"mempool_tx_added_total_{chain_id}")
return tx_hash
def list_transactions(self, chain_id: str = "ait-devnet") -> List[PendingTransaction]:
def list_transactions(self, chain_id: str = None) -> List[PendingTransaction]:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
with self._lock:
return list(self._transactions.values())
def drain(self, max_count: int, max_bytes: int, chain_id: str = "ait-devnet") -> List[PendingTransaction]:
def drain(self, max_count: int, max_bytes: int, chain_id: str = None) -> List[PendingTransaction]:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
"""Drain transactions for block inclusion, prioritized by fee (highest first)."""
with self._lock:
sorted_txs = sorted(
@@ -87,14 +96,20 @@ class InMemoryMempool:
metrics_registry.increment(f"mempool_tx_drained_total_{chain_id}", float(len(result)))
return result
def remove(self, tx_hash: str, chain_id: str = "ait-devnet") -> bool:
def remove(self, tx_hash: str, chain_id: str = None) -> bool:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
with self._lock:
removed = self._transactions.pop(tx_hash, None) is not None
if removed:
metrics_registry.set_gauge("mempool_size", float(len(self._transactions)))
return removed
def size(self, chain_id: str = "ait-devnet") -> int:
def size(self, chain_id: str = None) -> int:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
with self._lock:
return len(self._transactions)
@@ -135,7 +150,10 @@ class DatabaseMempool:
self._conn.execute("CREATE INDEX IF NOT EXISTS idx_mempool_fee ON mempool(fee DESC)")
self._conn.commit()
def add(self, tx: Dict[str, Any], chain_id: str = "ait-devnet") -> str:
def add(self, tx: Dict[str, Any], chain_id: str = None) -> str:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
fee = tx.get("fee", 0)
if fee < self._min_fee:
raise ValueError(f"Fee {fee} below minimum {self._min_fee}")
@@ -169,7 +187,10 @@ class DatabaseMempool:
self._update_gauge(chain_id)
return tx_hash
def list_transactions(self, chain_id: str = "ait-devnet") -> List[PendingTransaction]:
def list_transactions(self, chain_id: str = None) -> List[PendingTransaction]:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
with self._lock:
rows = self._conn.execute(
"SELECT tx_hash, content, fee, size_bytes, received_at FROM mempool WHERE chain_id = ? ORDER BY fee DESC, received_at ASC",
@@ -182,7 +203,10 @@ class DatabaseMempool:
) for r in rows
]
def drain(self, max_count: int, max_bytes: int, chain_id: str = "ait-devnet") -> List[PendingTransaction]:
def drain(self, max_count: int, max_bytes: int, chain_id: str = None) -> List[PendingTransaction]:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
with self._lock:
rows = self._conn.execute(
"SELECT tx_hash, content, fee, size_bytes, received_at FROM mempool WHERE chain_id = ? ORDER BY fee DESC, received_at ASC",
@@ -214,7 +238,10 @@ class DatabaseMempool:
self._update_gauge(chain_id)
return result
def remove(self, tx_hash: str, chain_id: str = "ait-devnet") -> bool:
def remove(self, tx_hash: str, chain_id: str = None) -> bool:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
with self._lock:
cursor = self._conn.execute("DELETE FROM mempool WHERE chain_id = ? AND tx_hash = ?", (chain_id, tx_hash))
self._conn.commit()
@@ -223,11 +250,17 @@ class DatabaseMempool:
self._update_gauge(chain_id)
return removed
def size(self, chain_id: str = "ait-devnet") -> int:
def size(self, chain_id: str = None) -> int:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
with self._lock:
return self._conn.execute("SELECT COUNT(*) FROM mempool WHERE chain_id = ?", (chain_id,)).fetchone()[0]
def _update_gauge(self, chain_id: str = "ait-devnet") -> None:
def _update_gauge(self, chain_id: str = None) -> None:
from .config import settings
if chain_id is None:
chain_id = settings.chain_id
count = self._conn.execute("SELECT COUNT(*) FROM mempool WHERE chain_id = ?", (chain_id,)).fetchone()[0]
metrics_registry.set_gauge(f"mempool_size_{chain_id}", float(count))

View File

@@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""
P2P Network Service using Redis Gossip
Handles peer-to-peer communication between blockchain nodes
"""
import asyncio
import json
import logging
import socket
from typing import Dict, Any, Optional
logger = logging.getLogger(__name__)
class P2PNetworkService:
def __init__(self, host: str, port: int, redis_url: str, node_id: str):
self.host = host
self.port = port
self.redis_url = redis_url
self.node_id = node_id
self._server = None
self._stop_event = asyncio.Event()
async def start(self):
"""Start P2P network service"""
logger.info(f"Starting P2P network service on {self.host}:{self.port}")
# Create TCP server for P2P connections
self._server = await asyncio.start_server(
self._handle_connection,
self.host,
self.port
)
logger.info(f"P2P service listening on {self.host}:{self.port}")
try:
await self._stop_event.wait()
finally:
await self.stop()
async def stop(self):
"""Stop P2P network service"""
logger.info("Stopping P2P network service")
if self._server:
self._server.close()
await self._server.wait_closed()
async def _handle_connection(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
"""Handle incoming P2P connections"""
addr = writer.get_extra_info('peername')
logger.info(f"P2P connection from {addr}")
try:
while True:
data = await reader.read(1024)
if not data:
break
try:
message = json.loads(data.decode())
logger.info(f"P2P received: {message}")
# Handle different message types
if message.get('type') == 'ping':
response = {'type': 'pong', 'node_id': self.node_id}
writer.write(json.dumps(response).encode() + b'\n')
await writer.drain()
except json.JSONDecodeError:
logger.warning(f"Invalid JSON from {addr}")
except asyncio.CancelledError:
pass
except Exception as e:
logger.error(f"P2P connection error: {e}")
finally:
writer.close()
await writer.wait_closed()
logger.info(f"P2P connection closed from {addr}")
async def run_p2p_service(host: str, port: int, redis_url: str, node_id: str):
"""Run P2P service"""
service = P2PNetworkService(host, port, redis_url, node_id)
await service.start()
def main():
import argparse
parser = argparse.ArgumentParser(description="AITBC P2P Network Service")
parser.add_argument("--host", default="0.0.0.0", help="Bind host")
parser.add_argument("--port", type=int, default=8005, help="Bind port")
parser.add_argument("--redis", default="redis://localhost:6379", help="Redis URL")
parser.add_argument("--node-id", help="Node identifier")
args = parser.parse_args()
logging.basicConfig(level=logging.INFO)
try:
asyncio.run(run_p2p_service(args.host, args.port, args.redis, args.node_id))
except KeyboardInterrupt:
logger.info("P2P service stopped by user")
if __name__ == "__main__":
main()

View File

@@ -18,6 +18,13 @@ from ..models import Account, Block, Receipt, Transaction
router = APIRouter()
def get_chain_id(chain_id: str = None) -> str:
"""Get chain_id from parameter or use default from settings"""
if chain_id is None:
from ..config import settings
return settings.chain_id
return chain_id
def _serialize_receipt(receipt: Receipt) -> Dict[str, Any]:
return {
@@ -63,7 +70,14 @@ class EstimateFeeRequest(BaseModel):
@router.get("/head", summary="Get current chain head")
async def get_head(chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def get_head(chain_id: str = None) -> Dict[str, Any]:
"""Get current chain head"""
from ..config import settings as cfg
# Use default chain_id from settings if not provided
if chain_id is None:
chain_id = cfg.chain_id
metrics_registry.increment("rpc_get_head_total")
start = time.perf_counter()
with session_scope() as session:
@@ -96,6 +110,7 @@ async def get_block(height: int) -> Dict[str, Any]:
"height": block.height,
"hash": block.hash,
"parent_hash": block.parent_hash,
"proposer": block.proposer,
"timestamp": block.timestamp.isoformat(),
"tx_count": block.tx_count,
"state_root": block.state_root,
@@ -140,6 +155,7 @@ async def get_blocks_range(start: int, end: int) -> Dict[str, Any]:
"height": block.height,
"hash": block.hash,
"parent_hash": block.parent_hash,
"proposer": block.proposer,
"timestamp": block.timestamp.isoformat(),
"tx_count": block.tx_count,
"state_root": block.state_root,
@@ -157,7 +173,8 @@ async def get_blocks_range(start: int, end: int) -> Dict[str, Any]:
@router.get("/tx/{tx_hash}", summary="Get transaction by hash")
async def get_transaction(tx_hash: str, chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def get_transaction(tx_hash: str, chain_id: str = None) -> Dict[str, Any]:
chain_id = get_chain_id(chain_id)
metrics_registry.increment("rpc_get_transaction_total")
start = time.perf_counter()
with session_scope() as session:
@@ -296,7 +313,8 @@ async def get_receipts(limit: int = 20, offset: int = 0) -> Dict[str, Any]:
@router.get("/getBalance/{address}", summary="Get account balance")
async def get_balance(address: str, chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def get_balance(address: str, chain_id: str = None) -> Dict[str, Any]:
chain_id = get_chain_id(chain_id)
metrics_registry.increment("rpc_get_balance_total")
start = time.perf_counter()
with session_scope() as session:
@@ -442,7 +460,7 @@ async def get_addresses(limit: int = 20, offset: int = 0, min_balance: int = 0)
@router.post("/sendTx", summary="Submit a new transaction")
async def send_transaction(request: TransactionRequest, chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def send_transaction(request: TransactionRequest, chain_id: str = None) -> Dict[str, Any]:
metrics_registry.increment("rpc_send_tx_total")
start = time.perf_counter()
mempool = get_mempool()
@@ -481,7 +499,7 @@ async def send_transaction(request: TransactionRequest, chain_id: str = "ait-dev
@router.post("/submitReceipt", summary="Submit receipt claim transaction")
async def submit_receipt(request: ReceiptSubmissionRequest, chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def submit_receipt(request: ReceiptSubmissionRequest, chain_id: str = None) -> Dict[str, Any]:
metrics_registry.increment("rpc_submit_receipt_total")
start = time.perf_counter()
tx_payload = {
@@ -539,7 +557,7 @@ class ImportBlockRequest(BaseModel):
@router.post("/importBlock", summary="Import a block from a remote peer")
async def import_block(request: ImportBlockRequest, chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def import_block(request: ImportBlockRequest, chain_id: str = None) -> Dict[str, Any]:
from ..sync import ChainSync, ProposerSignatureValidator
from ..config import settings as cfg
@@ -578,7 +596,7 @@ async def import_block(request: ImportBlockRequest, chain_id: str = "ait-devnet"
@router.get("/syncStatus", summary="Get chain sync status")
async def sync_status(chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def sync_status(chain_id: str = None) -> Dict[str, Any]:
from ..sync import ChainSync
from ..config import settings as cfg
@@ -588,7 +606,7 @@ async def sync_status(chain_id: str = "ait-devnet") -> Dict[str, Any]:
@router.get("/info", summary="Get blockchain information")
async def get_blockchain_info(chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def get_blockchain_info(chain_id: str = None) -> Dict[str, Any]:
"""Get comprehensive blockchain information"""
from ..config import settings as cfg
@@ -634,31 +652,48 @@ async def get_blockchain_info(chain_id: str = "ait-devnet") -> Dict[str, Any]:
@router.get("/supply", summary="Get token supply information")
async def get_token_supply(chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def get_token_supply(chain_id: str = None) -> Dict[str, Any]:
"""Get token supply information"""
from ..config import settings as cfg
from ..models import Account
chain_id = get_chain_id(chain_id)
metrics_registry.increment("rpc_supply_total")
start = time.perf_counter()
with session_scope() as session:
# Simple implementation for now
response = {
"chain_id": chain_id,
"total_supply": 1000000000, # 1 billion from genesis
"circulating_supply": 0, # No transactions yet
"faucet_balance": 1000000000, # All tokens in faucet
"faucet_address": "ait1faucet000000000000000000000000000000000",
"mint_per_unit": cfg.mint_per_unit,
"total_accounts": 0
}
# Calculate actual values from database
accounts = session.exec(select(Account).where(Account.chain_id == chain_id)).all()
total_balance = sum(account.balance for account in accounts)
total_accounts = len(accounts)
# Production implementation - calculate real circulating supply
if chain_id == "ait-mainnet":
response = {
"chain_id": chain_id,
"total_supply": 1000000000, # 1 billion from genesis
"circulating_supply": total_balance, # Actual tokens in circulation
"mint_per_unit": cfg.mint_per_unit,
"total_accounts": total_accounts # Actual account count
}
else:
# Devnet with faucet - use actual calculations
response = {
"chain_id": chain_id,
"total_supply": 1000000000, # 1 billion from genesis
"circulating_supply": total_balance, # Actual tokens in circulation
"faucet_balance": 1000000000, # All tokens in faucet
"faucet_address": "ait1faucet000000000000000000000000000000000",
"mint_per_unit": cfg.mint_per_unit,
"total_accounts": total_accounts # Actual account count
}
metrics_registry.observe("rpc_supply_duration_seconds", time.perf_counter() - start)
return response
@router.get("/validators", summary="List blockchain validators")
async def get_validators(chain_id: str = "ait-devnet") -> Dict[str, Any]:
async def get_validators(chain_id: str = None) -> Dict[str, Any]:
"""List blockchain validators (authorities)"""
from ..config import settings as cfg
@@ -690,7 +725,7 @@ async def get_validators(chain_id: str = "ait-devnet") -> Dict[str, Any]:
@router.get("/state", summary="Get blockchain state information")
async def get_chain_state(chain_id: str = "ait-devnet"):
async def get_chain_state(chain_id: str = None):
"""Get blockchain state information for a chain"""
start = time.perf_counter()
@@ -710,7 +745,7 @@ async def get_chain_state(chain_id: str = "ait-devnet"):
@router.get("/rpc/getBalance/{address}", summary="Get account balance")
async def get_balance(address: str, chain_id: str = "ait-devnet"):
async def get_balance(address: str, chain_id: str = None):
"""Get account balance for a specific address"""
start = time.perf_counter()
@@ -753,7 +788,7 @@ async def get_balance(address: str, chain_id: str = "ait-devnet"):
@router.get("/rpc/head", summary="Get current chain head")
async def get_head(chain_id: str = "ait-devnet"):
async def get_head(chain_id: str = None):
"""Get current chain head block"""
start = time.perf_counter()
@@ -799,7 +834,7 @@ async def get_head(chain_id: str = "ait-devnet"):
@router.get("/rpc/transactions", summary="Get latest transactions")
async def get_transactions(chain_id: str = "ait-devnet", limit: int = 20, offset: int = 0):
async def get_transactions(chain_id: str = None, limit: int = 20, offset: int = 0):
"""Get latest transactions"""
start = time.perf_counter()

View File

@@ -16,7 +16,7 @@ from sqlmodel import Session, select
from .config import settings
from .logger import get_logger
from .metrics import metrics_registry
from .models import Block, Transaction
from .models import Block, Transaction, Account
logger = get_logger(__name__)
@@ -284,15 +284,45 @@ class ChainSync:
)
session.add(block)
# Import transactions if provided
# Import transactions if provided and apply state changes
if transactions:
for tx_data in transactions:
sender_addr = tx_data.get("sender", "")
payload = tx_data.get("payload", {}) or {}
recipient_addr = payload.get("to") or tx_data.get("recipient", "")
value = int(payload.get("value", 0) or 0)
fee = int(tx_data.get("fee", 0) or 0)
tx_hash = tx_data.get("tx_hash", "")
# Upsert sender/recipient accounts
sender_acct = session.get(Account, (self._chain_id, sender_addr))
if sender_acct is None:
sender_acct = Account(chain_id=self._chain_id, address=sender_addr, balance=0, nonce=0)
session.add(sender_acct)
session.flush()
recipient_acct = session.get(Account, (self._chain_id, recipient_addr))
if recipient_acct is None:
recipient_acct = Account(chain_id=self._chain_id, address=recipient_addr, balance=0, nonce=0)
session.add(recipient_acct)
session.flush()
# Apply balances/nonce; assume block validity already verified on producer
total_cost = value + fee
sender_acct.balance -= total_cost
tx_nonce = tx_data.get("nonce")
if tx_nonce is not None:
sender_acct.nonce = max(sender_acct.nonce, int(tx_nonce) + 1)
else:
sender_acct.nonce += 1
recipient_acct.balance += value
tx = Transaction(
chain_id=self._chain_id,
tx_hash=tx_data.get("tx_hash", ""),
tx_hash=tx_hash,
block_height=block_data["height"],
sender=tx_data.get("sender", ""),
recipient=tx_data.get("recipient", ""),
sender=sender_addr,
recipient=recipient_addr,
payload=tx_data,
)
session.add(tx)

View File

@@ -9,12 +9,57 @@ from ..core.genesis_generator import GenesisGenerator, GenesisValidationError
from ..core.config import MultiChainConfig, load_multichain_config
from ..models.chain import GenesisConfig
from ..utils import output, error, success
from .keystore import create_keystore_via_script
import subprocess
import sys
@click.group()
def genesis():
"""Genesis block generation and management commands"""
pass
@genesis.command()
@click.option('--address', required=True, help='Wallet address (id) to create')
@click.option('--password-file', default='/opt/aitbc/data/keystore/.password', show_default=True, type=click.Path(exists=True, dir_okay=False), help='Path to password file')
@click.option('--output-dir', default='/opt/aitbc/data/keystore', show_default=True, help='Directory to write keystore file')
@click.option('--force', is_flag=True, help='Overwrite existing keystore file if present')
@click.pass_context
def create_keystore(ctx, address, password_file, output_dir, force):
"""Create an encrypted keystore for a genesis/treasury address."""
try:
create_keystore_via_script(address=address, password_file=password_file, output_dir=output_dir, force=force)
success(f"Created keystore for {address} at {output_dir}")
except Exception as e:
error(f"Error creating keystore: {e}")
raise click.Abort()
@genesis.command(name="init-production")
@click.option('--chain-id', default='ait-mainnet', show_default=True, help='Chain ID to initialize')
@click.option('--genesis-file', default='data/genesis_prod.yaml', show_default=True, help='Path to genesis YAML (copy to /opt/aitbc/genesis_prod.yaml if needed)')
@click.option('--db', default='/opt/aitbc/data/ait-mainnet/chain.db', show_default=True, help='SQLite DB path')
@click.option('--force', is_flag=True, help='Overwrite existing DB (removes file if present)')
@click.pass_context
def init_production(ctx, chain_id, genesis_file, db, force):
"""Initialize production chain DB using genesis allocations."""
db_path = Path(db)
if db_path.exists() and force:
db_path.unlink()
python_bin = Path(__file__).resolve().parents[3] / 'apps' / 'blockchain-node' / '.venv' / 'bin' / 'python3'
cmd = [
str(python_bin),
str(Path(__file__).resolve().parents[3] / 'scripts' / 'init_production_genesis.py'),
'--chain-id', chain_id,
'--db', db,
]
try:
subprocess.run(cmd, check=True)
success(f"Initialized production genesis for {chain_id} at {db}")
except subprocess.CalledProcessError as e:
error(f"Genesis init failed: {e}")
raise click.Abort()
@genesis.command()
@click.argument('config_file', type=click.Path(exists=True))
@click.option('--output', '-o', 'output_file', help='Output file path')

View File

@@ -0,0 +1,67 @@
import click
import importlib.util
from pathlib import Path
def _load_keystore_script():
"""Dynamically load the top-level scripts/keystore.py module."""
root = Path(__file__).resolve().parents[3] # /opt/aitbc
ks_path = root / "scripts" / "keystore.py"
spec = importlib.util.spec_from_file_location("aitbc_scripts_keystore", ks_path)
if spec is None or spec.loader is None:
raise ImportError(f"Unable to load keystore script from {ks_path}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
@click.group()
def keystore():
"""Keystore operations (create wallets/keystores)."""
pass
@keystore.command()
@click.option("--address", required=True, help="Wallet address (id) to create")
@click.option(
"--password-file",
default="/opt/aitbc/data/keystore/.password",
show_default=True,
type=click.Path(exists=True, dir_okay=False),
help="Path to password file",
)
@click.option(
"--output",
default="/opt/aitbc/data/keystore",
show_default=True,
help="Directory to write keystore files",
)
@click.option(
"--force",
is_flag=True,
help="Overwrite existing keystore file if present",
)
@click.pass_context
def create(ctx, address: str, password_file: str, output: str, force: bool):
"""Create an encrypted keystore for the given address.
Examples:
aitbc keystore create --address aitbc1genesis
aitbc keystore create --address aitbc1treasury --password-file keystore/.password --output keystore
"""
pwd_path = Path(password_file)
with open(pwd_path, "r", encoding="utf-8") as f:
password = f.read().strip()
out_dir = Path(output) if output else Path("/opt/aitbc/data/keystore")
out_dir.mkdir(parents=True, exist_ok=True)
ks_module = _load_keystore_script()
ks_module.create_keystore(address=address, password=password, keystore_dir=out_dir, force=force)
click.echo(f"Created keystore for {address} at {out_dir}")
# Helper so other commands (genesis) can reuse the same logic
def create_keystore_via_script(address: str, password_file: str = "/opt/aitbc/data/keystore/.password", output_dir: str = "/opt/aitbc/data/keystore", force: bool = False):
pwd = Path(password_file).read_text(encoding="utf-8").strip()
out_dir = Path(output_dir)
out_dir.mkdir(parents=True, exist_ok=True)
ks_module = _load_keystore_script()
ks_module.create_keystore(address=address, password=pwd, keystore_dir=out_dir, force=force)

View File

@@ -46,6 +46,7 @@ from .commands.marketplace_advanced import advanced # Re-enabled after fixing r
from .commands.swarm import swarm
from .commands.chain import chain
from .commands.genesis import genesis
from .commands.keystore import keystore
from .commands.test_cli import test
from .commands.node import node
from .commands.analytics import analytics
@@ -257,6 +258,7 @@ cli.add_command(ai_group)
cli.add_command(swarm)
cli.add_command(chain)
cli.add_command(genesis)
cli.add_command(keystore)
cli.add_command(test)
cli.add_command(node)
cli.add_command(analytics)

View File

@@ -38,10 +38,10 @@ def check_build_tests():
rc, out = sh("poetry check")
checks.append(("poetry check", rc == 0, out))
# 2) Fast syntax check of CLI package
rc, out = sh("python -m py_compile cli/aitbc_cli/__main__.py")
rc, out = sh("python3 -m py_compile cli/aitbc_cli/main.py")
checks.append(("cli syntax", rc == 0, out if rc != 0 else "OK"))
# 3) Minimal test run (dry-run or 1 quick test)
rc, out = sh("python -m pytest tests/ -v --collect-only 2>&1 | head -20")
rc, out = sh("python3 -m pytest tests/ -v --collect-only 2>&1 | head -20")
tests_ok = rc == 0
checks.append(("test discovery", tests_ok, out if not tests_ok else f"Collected {out.count('test') if 'test' in out else '?'} tests"))
all_ok = all(ok for _, ok, _ in checks)
@@ -86,7 +86,7 @@ def check_vulnerabilities():
"""Run security audits for Python and Node dependencies."""
issues = []
# Python: pip-audit (if available)
rc, out = sh("pip-audit --requirement <(poetry export --without-hashes) 2>&1", shell=True)
rc, out = sh("pip-audit --requirement <(poetry export --without-hashes) 2>&1")
if rc == 0:
# No vulnerabilities
pass

140
infra/helm/values/prod.yaml Normal file
View File

@@ -0,0 +1,140 @@
# Production environment values
global:
environment: production
coordinator:
replicaCount: 3
image:
tag: "v0.1.0"
resources:
limits:
cpu: 2000m
memory: 2Gi
requests:
cpu: 1000m
memory: 1Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 75
targetMemoryUtilizationPercentage: 80
config:
appEnv: production
allowOrigins: "https://app.aitbc.io"
postgresql:
auth:
existingSecret: "coordinator-db-secret"
primary:
persistence:
size: 200Gi
storageClass: fast-ssd
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 1000m
memory: 2Gi
readReplicas:
replicaCount: 2
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
monitoring:
prometheus:
server:
retention: 90d
persistentVolume:
size: 500Gi
storageClass: fast-ssd
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 1000m
memory: 2Gi
grafana:
adminPassword: "prod-admin-secure-2024"
persistence:
size: 50Gi
storageClass: fast-ssd
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
ingress:
enabled: true
hosts:
- grafana.aitbc.io
# Additional services
blockchainNode:
replicaCount: 5
resources:
limits:
cpu: 2000m
memory: 2Gi
requests:
cpu: 1000m
memory: 1Gi
autoscaling:
enabled: true
minReplicas: 5
maxReplicas: 50
targetCPUUtilizationPercentage: 70
walletDaemon:
replicaCount: 3
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 75
# Ingress configuration
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/rate-limit-window: "1m"
hosts:
- host: api.aitbc.io
paths:
- path: /
pathType: Prefix
tls:
- secretName: prod-tls
hosts:
- api.aitbc.io
# Security
podSecurityPolicy:
enabled: true
networkPolicy:
enabled: true
# Backup configuration
backup:
enabled: true
schedule: "0 2 * * *"
retention: "30d"

View File

@@ -0,0 +1,259 @@
# Production environment Helm values
global:
environment: prod
domain: aitbc.bubuit.net
imageTag: stable
imagePullPolicy: IfNotPresent
# Coordinator API
coordinator:
enabled: true
replicas: 3
image:
repository: aitbc/coordinator-api
tag: stable
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 2Gi
service:
type: ClusterIP
port: 8001
env:
LOG_LEVEL: warn
DATABASE_URL: secretRef:db-credentials
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilization: 60
targetMemoryUtilization: 70
livenessProbe:
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
initialDelaySeconds: 5
periodSeconds: 5
# Explorer Web
explorer:
enabled: true
replicas: 3
image:
repository: aitbc/explorer-web
tag: stable
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
service:
type: ClusterIP
port: 3000
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 8
# Marketplace Web
marketplace:
enabled: true
replicas: 3
image:
repository: aitbc/marketplace-web
tag: stable
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
service:
type: ClusterIP
port: 3001
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 8
# Wallet Daemon
wallet:
enabled: true
replicas: 2
image:
repository: aitbc/wallet-daemon
tag: stable
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 2Gi
service:
type: ClusterIP
port: 8002
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 6
# Trade Exchange
exchange:
enabled: true
replicas: 2
image:
repository: aitbc/trade-exchange
tag: stable
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
service:
type: ClusterIP
port: 8085
# PostgreSQL (prod uses RDS Multi-AZ)
postgresql:
enabled: false
external:
host: secretRef:db-credentials:host
port: 5432
database: coordinator
sslMode: require
# Redis (prod uses ElastiCache)
redis:
enabled: false
external:
host: secretRef:redis-credentials:host
port: 6379
auth: true
# Ingress
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-body-size: 10m
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/rate-limit-window: 1m
cert-manager.io/cluster-issuer: letsencrypt-prod
tls:
- secretName: prod-tls
hosts:
- aitbc.bubuit.net
hosts:
- host: aitbc.bubuit.net
paths:
- path: /api
service: coordinator
port: 8001
- path: /explorer
service: explorer
port: 3000
- path: /marketplace
service: marketplace
port: 3001
- path: /wallet
service: wallet
port: 8002
- path: /Exchange
service: exchange
port: 8085
# Monitoring
monitoring:
enabled: true
prometheus:
enabled: true
retention: 30d
resources:
requests:
cpu: 500m
memory: 2Gi
limits:
cpu: 2000m
memory: 4Gi
grafana:
enabled: true
persistence:
enabled: true
size: 10Gi
alertmanager:
enabled: true
config:
receivers:
- name: slack
slack_configs:
- channel: '#aitbc-alerts'
send_resolved: true
# Logging
logging:
enabled: true
level: warn
elasticsearch:
enabled: true
retention: 30d
replicas: 3
# Pod Disruption Budgets
podDisruptionBudget:
coordinator:
minAvailable: 2
explorer:
minAvailable: 2
marketplace:
minAvailable: 2
wallet:
minAvailable: 1
# Network Policies
networkPolicy:
enabled: true
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
egress:
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- port: 53
protocol: UDP
# Security
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
readOnlyRootFilesystem: true
# Affinity - spread across zones
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: coordinator
topologyKey: topology.kubernetes.io/zone
# Priority Classes
priorityClassName: high-priority

View File

@@ -0,0 +1,247 @@
# AITBC Nginx Reverse Proxy Configuration
# Domain: aitbc.keisanki.net
# This configuration replaces the need for firehol/iptables port forwarding
# HTTP to HTTPS redirect
server {
listen 80;
server_name aitbc.keisanki.net;
# Redirect all HTTP traffic to HTTPS
return 301 https://$server_name$request_uri;
}
# Main HTTPS server block
server {
listen 443 ssl http2;
server_name aitbc.keisanki.net;
# SSL Configuration (Let's Encrypt certificates)
ssl_certificate /etc/letsencrypt/live/aitbc.keisanki.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/aitbc.keisanki.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline' 'unsafe-eval'" always;
# Enable gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# Blockchain Explorer (main route)
location / {
proxy_pass http://192.168.100.10:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
# WebSocket support if needed
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Coordinator API
location /api/ {
proxy_pass http://192.168.100.10:8000/v1/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
# CORS headers for API
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Api-Key" always;
# Handle preflight requests
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Api-Key";
add_header Access-Control-Max-Age 1728000;
add_header Content-Type "text/plain; charset=utf-8";
add_header Content-Length 0;
return 204;
}
}
# Blockchain Node 1 RPC
location /rpc/ {
proxy_pass http://192.168.100.10:8082/rpc/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
# Blockchain Node 2 RPC (alternative endpoint)
location /rpc2/ {
proxy_pass http://192.168.100.10:8081/rpc/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
# Exchange API
location /exchange/ {
proxy_pass http://192.168.100.10:9080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
# Marketplace UI (if separate from explorer)
location /marketplace/ {
proxy_pass http://192.168.100.10:3001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
# Handle subdirectory rewrite
rewrite ^/marketplace/(.*)$ /$1 break;
}
# Admin dashboard
location /admin/ {
proxy_pass http://192.168.100.10:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
# Optional: Restrict admin access
# allow 192.168.100.0/24;
# allow 127.0.0.1;
# deny all;
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# API health checks
location /api/health {
proxy_pass http://192.168.100.10:8000/v1/health;
proxy_set_header Host $host;
access_log off;
}
# Static assets caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://192.168.100.10:3000;
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options nosniff;
# Don't log static file access
access_log off;
}
# Deny access to hidden files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# Custom error pages
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# Optional: Subdomain for API-only access
server {
listen 443 ssl http2;
server_name api.aitbc.keisanki.net;
# SSL Configuration (same certificates)
ssl_certificate /etc/letsencrypt/live/aitbc.keisanki.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/aitbc.keisanki.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# API routes only
location / {
proxy_pass http://192.168.100.10:8000/v1/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
# CORS headers
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Api-Key" always;
# Handle preflight requests
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Api-Key";
add_header Access-Control-Max-Age 1728000;
add_header Content-Type "text/plain; charset=utf-8";
add_header Content-Length 0;
return 204;
}
}
}
# Optional: Subdomain for blockchain RPC
server {
listen 443 ssl http2;
server_name rpc.aitbc.keisanki.net;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/aitbc.keisanki.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/aitbc.keisanki.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
# RPC routes
location / {
proxy_pass http://192.168.100.10:8082/rpc/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
}

View File

@@ -0,0 +1,133 @@
# AITBC Services Nginx Configuration
# Domain: https://aitbc.bubuit.net
server {
listen 80;
server_name aitbc.bubuit.net;
# Redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name aitbc.bubuit.net;
# SSL Configuration (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/aitbc.bubuit.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/aitbc.bubuit.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# API Routes
location /api/ {
proxy_pass http://127.0.0.1:8000/v1/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
# Blockchain RPC Routes
location /rpc/ {
proxy_pass http://127.0.0.1:9080/rpc/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
# Marketplace UI
location /Marketplace {
proxy_pass http://127.0.0.1:3001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Handle subdirectory
rewrite ^/Marketplace/(.*)$ /$1 break;
proxy_buffering off;
}
# Trade Exchange
location /Exchange {
proxy_pass http://127.0.0.1:3002/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Handle subdirectory
rewrite ^/Exchange/(.*)$ /$1 break;
proxy_buffering off;
}
# Exchange API Routes
location /api/trades/ {
proxy_pass http://127.0.0.1:3003/api/trades/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
location /api/orders {
proxy_pass http://127.0.0.1:3003/api/orders;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
# Wallet CLI API (if needed)
location /wallet/ {
proxy_pass http://127.0.0.1:8000/wallet/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Admin routes
location /admin/ {
proxy_pass http://127.0.0.1:8000/admin/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Restrict access (optional)
# allow 127.0.0.1;
# allow 10.1.223.0/24;
# deny all;
}
# Health check
location /health {
proxy_pass http://127.0.0.1:8000/v1/health;
proxy_set_header Host $host;
}
# Default redirect to Marketplace
location / {
return 301 /Marketplace;
}
# Static file caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}

View File

@@ -0,0 +1,324 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BytesLike,
FunctionFragment,
Result,
Interface,
EventFragment,
AddressLike,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedLogDescription,
TypedListener,
TypedContractMethod,
} from "../../../common";
export interface AccessControlInterface extends Interface {
getFunction(
nameOrSignature:
| "DEFAULT_ADMIN_ROLE"
| "getRoleAdmin"
| "grantRole"
| "hasRole"
| "renounceRole"
| "revokeRole"
| "supportsInterface"
): FunctionFragment;
getEvent(
nameOrSignatureOrTopic: "RoleAdminChanged" | "RoleGranted" | "RoleRevoked"
): EventFragment;
encodeFunctionData(
functionFragment: "DEFAULT_ADMIN_ROLE",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "getRoleAdmin",
values: [BytesLike]
): string;
encodeFunctionData(
functionFragment: "grantRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "hasRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "renounceRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "revokeRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "supportsInterface",
values: [BytesLike]
): string;
decodeFunctionResult(
functionFragment: "DEFAULT_ADMIN_ROLE",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "getRoleAdmin",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "grantRole", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "hasRole", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "renounceRole",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "revokeRole", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "supportsInterface",
data: BytesLike
): Result;
}
export namespace RoleAdminChangedEvent {
export type InputTuple = [
role: BytesLike,
previousAdminRole: BytesLike,
newAdminRole: BytesLike
];
export type OutputTuple = [
role: string,
previousAdminRole: string,
newAdminRole: string
];
export interface OutputObject {
role: string;
previousAdminRole: string;
newAdminRole: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleGrantedEvent {
export type InputTuple = [
role: BytesLike,
account: AddressLike,
sender: AddressLike
];
export type OutputTuple = [role: string, account: string, sender: string];
export interface OutputObject {
role: string;
account: string;
sender: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleRevokedEvent {
export type InputTuple = [
role: BytesLike,
account: AddressLike,
sender: AddressLike
];
export type OutputTuple = [role: string, account: string, sender: string];
export interface OutputObject {
role: string;
account: string;
sender: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export interface AccessControl extends BaseContract {
connect(runner?: ContractRunner | null): AccessControl;
waitForDeployment(): Promise<this>;
interface: AccessControlInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
DEFAULT_ADMIN_ROLE: TypedContractMethod<[], [string], "view">;
getRoleAdmin: TypedContractMethod<[role: BytesLike], [string], "view">;
grantRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
hasRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[boolean],
"view"
>;
renounceRole: TypedContractMethod<
[role: BytesLike, callerConfirmation: AddressLike],
[void],
"nonpayable"
>;
revokeRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
supportsInterface: TypedContractMethod<
[interfaceId: BytesLike],
[boolean],
"view"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "DEFAULT_ADMIN_ROLE"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "getRoleAdmin"
): TypedContractMethod<[role: BytesLike], [string], "view">;
getFunction(
nameOrSignature: "grantRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "hasRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[boolean],
"view"
>;
getFunction(
nameOrSignature: "renounceRole"
): TypedContractMethod<
[role: BytesLike, callerConfirmation: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "revokeRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "supportsInterface"
): TypedContractMethod<[interfaceId: BytesLike], [boolean], "view">;
getEvent(
key: "RoleAdminChanged"
): TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
getEvent(
key: "RoleGranted"
): TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
getEvent(
key: "RoleRevoked"
): TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
filters: {
"RoleAdminChanged(bytes32,bytes32,bytes32)": TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
RoleAdminChanged: TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
"RoleGranted(bytes32,address,address)": TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
RoleGranted: TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
"RoleRevoked(bytes32,address,address)": TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
RoleRevoked: TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
};
}

View File

@@ -0,0 +1,292 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BytesLike,
FunctionFragment,
Result,
Interface,
EventFragment,
AddressLike,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedLogDescription,
TypedListener,
TypedContractMethod,
} from "../../../common";
export interface IAccessControlInterface extends Interface {
getFunction(
nameOrSignature:
| "getRoleAdmin"
| "grantRole"
| "hasRole"
| "renounceRole"
| "revokeRole"
): FunctionFragment;
getEvent(
nameOrSignatureOrTopic: "RoleAdminChanged" | "RoleGranted" | "RoleRevoked"
): EventFragment;
encodeFunctionData(
functionFragment: "getRoleAdmin",
values: [BytesLike]
): string;
encodeFunctionData(
functionFragment: "grantRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "hasRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "renounceRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "revokeRole",
values: [BytesLike, AddressLike]
): string;
decodeFunctionResult(
functionFragment: "getRoleAdmin",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "grantRole", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "hasRole", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "renounceRole",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "revokeRole", data: BytesLike): Result;
}
export namespace RoleAdminChangedEvent {
export type InputTuple = [
role: BytesLike,
previousAdminRole: BytesLike,
newAdminRole: BytesLike
];
export type OutputTuple = [
role: string,
previousAdminRole: string,
newAdminRole: string
];
export interface OutputObject {
role: string;
previousAdminRole: string;
newAdminRole: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleGrantedEvent {
export type InputTuple = [
role: BytesLike,
account: AddressLike,
sender: AddressLike
];
export type OutputTuple = [role: string, account: string, sender: string];
export interface OutputObject {
role: string;
account: string;
sender: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleRevokedEvent {
export type InputTuple = [
role: BytesLike,
account: AddressLike,
sender: AddressLike
];
export type OutputTuple = [role: string, account: string, sender: string];
export interface OutputObject {
role: string;
account: string;
sender: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export interface IAccessControl extends BaseContract {
connect(runner?: ContractRunner | null): IAccessControl;
waitForDeployment(): Promise<this>;
interface: IAccessControlInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
getRoleAdmin: TypedContractMethod<[role: BytesLike], [string], "view">;
grantRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
hasRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[boolean],
"view"
>;
renounceRole: TypedContractMethod<
[role: BytesLike, callerConfirmation: AddressLike],
[void],
"nonpayable"
>;
revokeRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "getRoleAdmin"
): TypedContractMethod<[role: BytesLike], [string], "view">;
getFunction(
nameOrSignature: "grantRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "hasRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[boolean],
"view"
>;
getFunction(
nameOrSignature: "renounceRole"
): TypedContractMethod<
[role: BytesLike, callerConfirmation: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "revokeRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getEvent(
key: "RoleAdminChanged"
): TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
getEvent(
key: "RoleGranted"
): TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
getEvent(
key: "RoleRevoked"
): TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
filters: {
"RoleAdminChanged(bytes32,bytes32,bytes32)": TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
RoleAdminChanged: TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
"RoleGranted(bytes32,address,address)": TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
RoleGranted: TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
"RoleRevoked(bytes32,address,address)": TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
RoleRevoked: TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
};
}

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export type { AccessControl } from "./AccessControl";
export type { IAccessControl } from "./IAccessControl";

View File

@@ -0,0 +1,11 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type * as access from "./access";
export type { access };
import type * as interfaces from "./interfaces";
export type { interfaces };
import type * as token from "./token";
export type { token };
import type * as utils from "./utils";
export type { utils };

View File

@@ -0,0 +1,69 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
FunctionFragment,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
} from "../../../../common";
export interface IERC1155ErrorsInterface extends Interface {}
export interface IERC1155Errors extends BaseContract {
connect(runner?: ContractRunner | null): IERC1155Errors;
waitForDeployment(): Promise<this>;
interface: IERC1155ErrorsInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
filters: {};
}

View File

@@ -0,0 +1,69 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
FunctionFragment,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
} from "../../../../common";
export interface IERC20ErrorsInterface extends Interface {}
export interface IERC20Errors extends BaseContract {
connect(runner?: ContractRunner | null): IERC20Errors;
waitForDeployment(): Promise<this>;
interface: IERC20ErrorsInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
filters: {};
}

View File

@@ -0,0 +1,69 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
FunctionFragment,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
} from "../../../../common";
export interface IERC721ErrorsInterface extends Interface {}
export interface IERC721Errors extends BaseContract {
connect(runner?: ContractRunner | null): IERC721Errors;
waitForDeployment(): Promise<this>;
interface: IERC721ErrorsInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
filters: {};
}

View File

@@ -0,0 +1,6 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export type { IERC1155Errors } from "./IERC1155Errors";
export type { IERC20Errors } from "./IERC20Errors";
export type { IERC721Errors } from "./IERC721Errors";

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type * as draftIerc6093Sol from "./draft-IERC6093.sol";
export type { draftIerc6093Sol };

View File

@@ -0,0 +1,286 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumberish,
BytesLike,
FunctionFragment,
Result,
Interface,
EventFragment,
AddressLike,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedLogDescription,
TypedListener,
TypedContractMethod,
} from "../../../../common";
export interface ERC20Interface extends Interface {
getFunction(
nameOrSignature:
| "allowance"
| "approve"
| "balanceOf"
| "decimals"
| "name"
| "symbol"
| "totalSupply"
| "transfer"
| "transferFrom"
): FunctionFragment;
getEvent(nameOrSignatureOrTopic: "Approval" | "Transfer"): EventFragment;
encodeFunctionData(
functionFragment: "allowance",
values: [AddressLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "approve",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "balanceOf",
values: [AddressLike]
): string;
encodeFunctionData(functionFragment: "decimals", values?: undefined): string;
encodeFunctionData(functionFragment: "name", values?: undefined): string;
encodeFunctionData(functionFragment: "symbol", values?: undefined): string;
encodeFunctionData(
functionFragment: "totalSupply",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "transfer",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "transferFrom",
values: [AddressLike, AddressLike, BigNumberish]
): string;
decodeFunctionResult(functionFragment: "allowance", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "approve", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "balanceOf", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "decimals", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "name", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "symbol", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "totalSupply",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "transfer", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "transferFrom",
data: BytesLike
): Result;
}
export namespace ApprovalEvent {
export type InputTuple = [
owner: AddressLike,
spender: AddressLike,
value: BigNumberish
];
export type OutputTuple = [owner: string, spender: string, value: bigint];
export interface OutputObject {
owner: string;
spender: string;
value: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace TransferEvent {
export type InputTuple = [
from: AddressLike,
to: AddressLike,
value: BigNumberish
];
export type OutputTuple = [from: string, to: string, value: bigint];
export interface OutputObject {
from: string;
to: string;
value: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export interface ERC20 extends BaseContract {
connect(runner?: ContractRunner | null): ERC20;
waitForDeployment(): Promise<this>;
interface: ERC20Interface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
allowance: TypedContractMethod<
[owner: AddressLike, spender: AddressLike],
[bigint],
"view"
>;
approve: TypedContractMethod<
[spender: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
balanceOf: TypedContractMethod<[account: AddressLike], [bigint], "view">;
decimals: TypedContractMethod<[], [bigint], "view">;
name: TypedContractMethod<[], [string], "view">;
symbol: TypedContractMethod<[], [string], "view">;
totalSupply: TypedContractMethod<[], [bigint], "view">;
transfer: TypedContractMethod<
[to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
transferFrom: TypedContractMethod<
[from: AddressLike, to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "allowance"
): TypedContractMethod<
[owner: AddressLike, spender: AddressLike],
[bigint],
"view"
>;
getFunction(
nameOrSignature: "approve"
): TypedContractMethod<
[spender: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction(
nameOrSignature: "balanceOf"
): TypedContractMethod<[account: AddressLike], [bigint], "view">;
getFunction(
nameOrSignature: "decimals"
): TypedContractMethod<[], [bigint], "view">;
getFunction(
nameOrSignature: "name"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "symbol"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "totalSupply"
): TypedContractMethod<[], [bigint], "view">;
getFunction(
nameOrSignature: "transfer"
): TypedContractMethod<
[to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction(
nameOrSignature: "transferFrom"
): TypedContractMethod<
[from: AddressLike, to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getEvent(
key: "Approval"
): TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
getEvent(
key: "Transfer"
): TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
filters: {
"Approval(address,address,uint256)": TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
Approval: TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
"Transfer(address,address,uint256)": TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
Transfer: TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
};
}

View File

@@ -0,0 +1,262 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumberish,
BytesLike,
FunctionFragment,
Result,
Interface,
EventFragment,
AddressLike,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedLogDescription,
TypedListener,
TypedContractMethod,
} from "../../../../common";
export interface IERC20Interface extends Interface {
getFunction(
nameOrSignature:
| "allowance"
| "approve"
| "balanceOf"
| "totalSupply"
| "transfer"
| "transferFrom"
): FunctionFragment;
getEvent(nameOrSignatureOrTopic: "Approval" | "Transfer"): EventFragment;
encodeFunctionData(
functionFragment: "allowance",
values: [AddressLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "approve",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "balanceOf",
values: [AddressLike]
): string;
encodeFunctionData(
functionFragment: "totalSupply",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "transfer",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "transferFrom",
values: [AddressLike, AddressLike, BigNumberish]
): string;
decodeFunctionResult(functionFragment: "allowance", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "approve", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "balanceOf", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "totalSupply",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "transfer", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "transferFrom",
data: BytesLike
): Result;
}
export namespace ApprovalEvent {
export type InputTuple = [
owner: AddressLike,
spender: AddressLike,
value: BigNumberish
];
export type OutputTuple = [owner: string, spender: string, value: bigint];
export interface OutputObject {
owner: string;
spender: string;
value: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace TransferEvent {
export type InputTuple = [
from: AddressLike,
to: AddressLike,
value: BigNumberish
];
export type OutputTuple = [from: string, to: string, value: bigint];
export interface OutputObject {
from: string;
to: string;
value: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export interface IERC20 extends BaseContract {
connect(runner?: ContractRunner | null): IERC20;
waitForDeployment(): Promise<this>;
interface: IERC20Interface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
allowance: TypedContractMethod<
[owner: AddressLike, spender: AddressLike],
[bigint],
"view"
>;
approve: TypedContractMethod<
[spender: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
balanceOf: TypedContractMethod<[account: AddressLike], [bigint], "view">;
totalSupply: TypedContractMethod<[], [bigint], "view">;
transfer: TypedContractMethod<
[to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
transferFrom: TypedContractMethod<
[from: AddressLike, to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "allowance"
): TypedContractMethod<
[owner: AddressLike, spender: AddressLike],
[bigint],
"view"
>;
getFunction(
nameOrSignature: "approve"
): TypedContractMethod<
[spender: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction(
nameOrSignature: "balanceOf"
): TypedContractMethod<[account: AddressLike], [bigint], "view">;
getFunction(
nameOrSignature: "totalSupply"
): TypedContractMethod<[], [bigint], "view">;
getFunction(
nameOrSignature: "transfer"
): TypedContractMethod<
[to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction(
nameOrSignature: "transferFrom"
): TypedContractMethod<
[from: AddressLike, to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getEvent(
key: "Approval"
): TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
getEvent(
key: "Transfer"
): TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
filters: {
"Approval(address,address,uint256)": TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
Approval: TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
"Transfer(address,address,uint256)": TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
Transfer: TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
};
}

View File

@@ -0,0 +1,286 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumberish,
BytesLike,
FunctionFragment,
Result,
Interface,
EventFragment,
AddressLike,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedLogDescription,
TypedListener,
TypedContractMethod,
} from "../../../../../common";
export interface IERC20MetadataInterface extends Interface {
getFunction(
nameOrSignature:
| "allowance"
| "approve"
| "balanceOf"
| "decimals"
| "name"
| "symbol"
| "totalSupply"
| "transfer"
| "transferFrom"
): FunctionFragment;
getEvent(nameOrSignatureOrTopic: "Approval" | "Transfer"): EventFragment;
encodeFunctionData(
functionFragment: "allowance",
values: [AddressLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "approve",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "balanceOf",
values: [AddressLike]
): string;
encodeFunctionData(functionFragment: "decimals", values?: undefined): string;
encodeFunctionData(functionFragment: "name", values?: undefined): string;
encodeFunctionData(functionFragment: "symbol", values?: undefined): string;
encodeFunctionData(
functionFragment: "totalSupply",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "transfer",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "transferFrom",
values: [AddressLike, AddressLike, BigNumberish]
): string;
decodeFunctionResult(functionFragment: "allowance", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "approve", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "balanceOf", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "decimals", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "name", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "symbol", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "totalSupply",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "transfer", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "transferFrom",
data: BytesLike
): Result;
}
export namespace ApprovalEvent {
export type InputTuple = [
owner: AddressLike,
spender: AddressLike,
value: BigNumberish
];
export type OutputTuple = [owner: string, spender: string, value: bigint];
export interface OutputObject {
owner: string;
spender: string;
value: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace TransferEvent {
export type InputTuple = [
from: AddressLike,
to: AddressLike,
value: BigNumberish
];
export type OutputTuple = [from: string, to: string, value: bigint];
export interface OutputObject {
from: string;
to: string;
value: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export interface IERC20Metadata extends BaseContract {
connect(runner?: ContractRunner | null): IERC20Metadata;
waitForDeployment(): Promise<this>;
interface: IERC20MetadataInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
allowance: TypedContractMethod<
[owner: AddressLike, spender: AddressLike],
[bigint],
"view"
>;
approve: TypedContractMethod<
[spender: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
balanceOf: TypedContractMethod<[account: AddressLike], [bigint], "view">;
decimals: TypedContractMethod<[], [bigint], "view">;
name: TypedContractMethod<[], [string], "view">;
symbol: TypedContractMethod<[], [string], "view">;
totalSupply: TypedContractMethod<[], [bigint], "view">;
transfer: TypedContractMethod<
[to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
transferFrom: TypedContractMethod<
[from: AddressLike, to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "allowance"
): TypedContractMethod<
[owner: AddressLike, spender: AddressLike],
[bigint],
"view"
>;
getFunction(
nameOrSignature: "approve"
): TypedContractMethod<
[spender: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction(
nameOrSignature: "balanceOf"
): TypedContractMethod<[account: AddressLike], [bigint], "view">;
getFunction(
nameOrSignature: "decimals"
): TypedContractMethod<[], [bigint], "view">;
getFunction(
nameOrSignature: "name"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "symbol"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "totalSupply"
): TypedContractMethod<[], [bigint], "view">;
getFunction(
nameOrSignature: "transfer"
): TypedContractMethod<
[to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction(
nameOrSignature: "transferFrom"
): TypedContractMethod<
[from: AddressLike, to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getEvent(
key: "Approval"
): TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
getEvent(
key: "Transfer"
): TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
filters: {
"Approval(address,address,uint256)": TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
Approval: TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
"Transfer(address,address,uint256)": TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
Transfer: TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
};
}

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export type { IERC20Metadata } from "./IERC20Metadata";

View File

@@ -0,0 +1,7 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type * as extensions from "./extensions";
export type { extensions };
export type { ERC20 } from "./ERC20";
export type { IERC20 } from "./IERC20";

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type * as erc20 from "./ERC20";
export type { erc20 };

View File

@@ -0,0 +1,69 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
FunctionFragment,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
} from "../../../common";
export interface StringsInterface extends Interface {}
export interface Strings extends BaseContract {
connect(runner?: ContractRunner | null): Strings;
waitForDeployment(): Promise<this>;
interface: StringsInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
filters: {};
}

View File

@@ -0,0 +1,69 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
FunctionFragment,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
} from "../../../../common";
export interface ECDSAInterface extends Interface {}
export interface ECDSA extends BaseContract {
connect(runner?: ContractRunner | null): ECDSA;
waitForDeployment(): Promise<this>;
interface: ECDSAInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
filters: {};
}

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export type { ECDSA } from "./ECDSA";

View File

@@ -0,0 +1,10 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type * as cryptography from "./cryptography";
export type { cryptography };
import type * as introspection from "./introspection";
export type { introspection };
import type * as math from "./math";
export type { math };
export type { Strings } from "./Strings";

View File

@@ -0,0 +1,94 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BytesLike,
FunctionFragment,
Result,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
TypedContractMethod,
} from "../../../../common";
export interface ERC165Interface extends Interface {
getFunction(nameOrSignature: "supportsInterface"): FunctionFragment;
encodeFunctionData(
functionFragment: "supportsInterface",
values: [BytesLike]
): string;
decodeFunctionResult(
functionFragment: "supportsInterface",
data: BytesLike
): Result;
}
export interface ERC165 extends BaseContract {
connect(runner?: ContractRunner | null): ERC165;
waitForDeployment(): Promise<this>;
interface: ERC165Interface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
supportsInterface: TypedContractMethod<
[interfaceId: BytesLike],
[boolean],
"view"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "supportsInterface"
): TypedContractMethod<[interfaceId: BytesLike], [boolean], "view">;
filters: {};
}

View File

@@ -0,0 +1,94 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BytesLike,
FunctionFragment,
Result,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
TypedContractMethod,
} from "../../../../common";
export interface IERC165Interface extends Interface {
getFunction(nameOrSignature: "supportsInterface"): FunctionFragment;
encodeFunctionData(
functionFragment: "supportsInterface",
values: [BytesLike]
): string;
decodeFunctionResult(
functionFragment: "supportsInterface",
data: BytesLike
): Result;
}
export interface IERC165 extends BaseContract {
connect(runner?: ContractRunner | null): IERC165;
waitForDeployment(): Promise<this>;
interface: IERC165Interface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
supportsInterface: TypedContractMethod<
[interfaceId: BytesLike],
[boolean],
"view"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "supportsInterface"
): TypedContractMethod<[interfaceId: BytesLike], [boolean], "view">;
filters: {};
}

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export type { ERC165 } from "./ERC165";
export type { IERC165 } from "./IERC165";

View File

@@ -0,0 +1,69 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
FunctionFragment,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
} from "../../../../common";
export interface SafeCastInterface extends Interface {}
export interface SafeCast extends BaseContract {
connect(runner?: ContractRunner | null): SafeCast;
waitForDeployment(): Promise<this>;
interface: SafeCastInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
filters: {};
}

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export type { SafeCast } from "./SafeCast";

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type * as contracts from "./contracts";
export type { contracts };

View File

@@ -0,0 +1,131 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
FunctionFragment,
Typed,
EventFragment,
ContractTransaction,
ContractTransactionResponse,
DeferredTopicFilter,
EventLog,
TransactionRequest,
LogDescription,
} from "ethers";
export interface TypedDeferredTopicFilter<_TCEvent extends TypedContractEvent>
extends DeferredTopicFilter {}
export interface TypedContractEvent<
InputTuple extends Array<any> = any,
OutputTuple extends Array<any> = any,
OutputObject = any
> {
(...args: Partial<InputTuple>): TypedDeferredTopicFilter<
TypedContractEvent<InputTuple, OutputTuple, OutputObject>
>;
name: string;
fragment: EventFragment;
getFragment(...args: Partial<InputTuple>): EventFragment;
}
type __TypechainAOutputTuple<T> = T extends TypedContractEvent<
infer _U,
infer W
>
? W
: never;
type __TypechainOutputObject<T> = T extends TypedContractEvent<
infer _U,
infer _W,
infer V
>
? V
: never;
export interface TypedEventLog<TCEvent extends TypedContractEvent>
extends Omit<EventLog, "args"> {
args: __TypechainAOutputTuple<TCEvent> & __TypechainOutputObject<TCEvent>;
}
export interface TypedLogDescription<TCEvent extends TypedContractEvent>
extends Omit<LogDescription, "args"> {
args: __TypechainAOutputTuple<TCEvent> & __TypechainOutputObject<TCEvent>;
}
export type TypedListener<TCEvent extends TypedContractEvent> = (
...listenerArg: [
...__TypechainAOutputTuple<TCEvent>,
TypedEventLog<TCEvent>,
...undefined[]
]
) => void;
export type MinEthersFactory<C, ARGS> = {
deploy(...a: ARGS[]): Promise<C>;
};
export type GetContractTypeFromFactory<F> = F extends MinEthersFactory<
infer C,
any
>
? C
: never;
export type GetARGsTypeFromFactory<F> = F extends MinEthersFactory<any, any>
? Parameters<F["deploy"]>
: never;
export type StateMutability = "nonpayable" | "payable" | "view";
export type BaseOverrides = Omit<TransactionRequest, "to" | "data">;
export type NonPayableOverrides = Omit<
BaseOverrides,
"value" | "blockTag" | "enableCcipRead"
>;
export type PayableOverrides = Omit<
BaseOverrides,
"blockTag" | "enableCcipRead"
>;
export type ViewOverrides = Omit<TransactionRequest, "to" | "data">;
export type Overrides<S extends StateMutability> = S extends "nonpayable"
? NonPayableOverrides
: S extends "payable"
? PayableOverrides
: ViewOverrides;
export type PostfixOverrides<A extends Array<any>, S extends StateMutability> =
| A
| [...A, Overrides<S>];
export type ContractMethodArgs<
A extends Array<any>,
S extends StateMutability
> = PostfixOverrides<{ [I in keyof A]-?: A[I] | Typed }, S>;
export type DefaultReturnType<R> = R extends Array<any> ? R[0] : R;
// export interface ContractMethod<A extends Array<any> = Array<any>, R = any, D extends R | ContractTransactionResponse = R | ContractTransactionResponse> {
export interface TypedContractMethod<
A extends Array<any> = Array<any>,
R = any,
S extends StateMutability = "payable"
> {
(...args: ContractMethodArgs<A, S>): S extends "view"
? Promise<DefaultReturnType<R>>
: Promise<ContractTransactionResponse>;
name: string;
fragment: FunctionFragment;
getFragment(...args: ContractMethodArgs<A, S>): FunctionFragment;
populateTransaction(
...args: ContractMethodArgs<A, S>
): Promise<ContractTransaction>;
staticCall(
...args: ContractMethodArgs<A, "view">
): Promise<DefaultReturnType<R>>;
send(...args: ContractMethodArgs<A, S>): Promise<ContractTransactionResponse>;
estimateGas(...args: ContractMethodArgs<A, S>): Promise<bigint>;
staticCallResult(...args: ContractMethodArgs<A, "view">): Promise<R>;
}

View File

@@ -0,0 +1,667 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumberish,
BytesLike,
FunctionFragment,
Result,
Interface,
EventFragment,
AddressLike,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedLogDescription,
TypedListener,
TypedContractMethod,
} from "../common";
export interface AITokenInterface extends Interface {
getFunction(
nameOrSignature:
| "ATTESTOR_ROLE"
| "COORDINATOR_ROLE"
| "DEFAULT_ADMIN_ROLE"
| "allowance"
| "approve"
| "balanceOf"
| "consumedReceipts"
| "decimals"
| "getRoleAdmin"
| "grantRole"
| "hasRole"
| "mintDigest"
| "mintWithReceipt"
| "name"
| "renounceRole"
| "revokeRole"
| "supportsInterface"
| "symbol"
| "totalSupply"
| "transfer"
| "transferFrom"
): FunctionFragment;
getEvent(
nameOrSignatureOrTopic:
| "Approval"
| "ReceiptConsumed"
| "RoleAdminChanged"
| "RoleGranted"
| "RoleRevoked"
| "Transfer"
): EventFragment;
encodeFunctionData(
functionFragment: "ATTESTOR_ROLE",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "COORDINATOR_ROLE",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "DEFAULT_ADMIN_ROLE",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "allowance",
values: [AddressLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "approve",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "balanceOf",
values: [AddressLike]
): string;
encodeFunctionData(
functionFragment: "consumedReceipts",
values: [BytesLike]
): string;
encodeFunctionData(functionFragment: "decimals", values?: undefined): string;
encodeFunctionData(
functionFragment: "getRoleAdmin",
values: [BytesLike]
): string;
encodeFunctionData(
functionFragment: "grantRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "hasRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "mintDigest",
values: [AddressLike, BigNumberish, BytesLike]
): string;
encodeFunctionData(
functionFragment: "mintWithReceipt",
values: [AddressLike, BigNumberish, BytesLike, BytesLike]
): string;
encodeFunctionData(functionFragment: "name", values?: undefined): string;
encodeFunctionData(
functionFragment: "renounceRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "revokeRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "supportsInterface",
values: [BytesLike]
): string;
encodeFunctionData(functionFragment: "symbol", values?: undefined): string;
encodeFunctionData(
functionFragment: "totalSupply",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "transfer",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "transferFrom",
values: [AddressLike, AddressLike, BigNumberish]
): string;
decodeFunctionResult(
functionFragment: "ATTESTOR_ROLE",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "COORDINATOR_ROLE",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "DEFAULT_ADMIN_ROLE",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "allowance", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "approve", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "balanceOf", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "consumedReceipts",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "decimals", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "getRoleAdmin",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "grantRole", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "hasRole", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "mintDigest", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "mintWithReceipt",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "name", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "renounceRole",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "revokeRole", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "supportsInterface",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "symbol", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "totalSupply",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "transfer", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "transferFrom",
data: BytesLike
): Result;
}
export namespace ApprovalEvent {
export type InputTuple = [
owner: AddressLike,
spender: AddressLike,
value: BigNumberish
];
export type OutputTuple = [owner: string, spender: string, value: bigint];
export interface OutputObject {
owner: string;
spender: string;
value: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace ReceiptConsumedEvent {
export type InputTuple = [
receiptHash: BytesLike,
provider: AddressLike,
units: BigNumberish,
attestor: AddressLike
];
export type OutputTuple = [
receiptHash: string,
provider: string,
units: bigint,
attestor: string
];
export interface OutputObject {
receiptHash: string;
provider: string;
units: bigint;
attestor: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleAdminChangedEvent {
export type InputTuple = [
role: BytesLike,
previousAdminRole: BytesLike,
newAdminRole: BytesLike
];
export type OutputTuple = [
role: string,
previousAdminRole: string,
newAdminRole: string
];
export interface OutputObject {
role: string;
previousAdminRole: string;
newAdminRole: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleGrantedEvent {
export type InputTuple = [
role: BytesLike,
account: AddressLike,
sender: AddressLike
];
export type OutputTuple = [role: string, account: string, sender: string];
export interface OutputObject {
role: string;
account: string;
sender: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleRevokedEvent {
export type InputTuple = [
role: BytesLike,
account: AddressLike,
sender: AddressLike
];
export type OutputTuple = [role: string, account: string, sender: string];
export interface OutputObject {
role: string;
account: string;
sender: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace TransferEvent {
export type InputTuple = [
from: AddressLike,
to: AddressLike,
value: BigNumberish
];
export type OutputTuple = [from: string, to: string, value: bigint];
export interface OutputObject {
from: string;
to: string;
value: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export interface AIToken extends BaseContract {
connect(runner?: ContractRunner | null): AIToken;
waitForDeployment(): Promise<this>;
interface: AITokenInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
ATTESTOR_ROLE: TypedContractMethod<[], [string], "view">;
COORDINATOR_ROLE: TypedContractMethod<[], [string], "view">;
DEFAULT_ADMIN_ROLE: TypedContractMethod<[], [string], "view">;
allowance: TypedContractMethod<
[owner: AddressLike, spender: AddressLike],
[bigint],
"view"
>;
approve: TypedContractMethod<
[spender: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
balanceOf: TypedContractMethod<[account: AddressLike], [bigint], "view">;
consumedReceipts: TypedContractMethod<[arg0: BytesLike], [boolean], "view">;
decimals: TypedContractMethod<[], [bigint], "view">;
getRoleAdmin: TypedContractMethod<[role: BytesLike], [string], "view">;
grantRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
hasRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[boolean],
"view"
>;
mintDigest: TypedContractMethod<
[provider: AddressLike, units: BigNumberish, receiptHash: BytesLike],
[string],
"view"
>;
mintWithReceipt: TypedContractMethod<
[
provider: AddressLike,
units: BigNumberish,
receiptHash: BytesLike,
signature: BytesLike
],
[void],
"nonpayable"
>;
name: TypedContractMethod<[], [string], "view">;
renounceRole: TypedContractMethod<
[role: BytesLike, callerConfirmation: AddressLike],
[void],
"nonpayable"
>;
revokeRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
supportsInterface: TypedContractMethod<
[interfaceId: BytesLike],
[boolean],
"view"
>;
symbol: TypedContractMethod<[], [string], "view">;
totalSupply: TypedContractMethod<[], [bigint], "view">;
transfer: TypedContractMethod<
[to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
transferFrom: TypedContractMethod<
[from: AddressLike, to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "ATTESTOR_ROLE"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "COORDINATOR_ROLE"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "DEFAULT_ADMIN_ROLE"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "allowance"
): TypedContractMethod<
[owner: AddressLike, spender: AddressLike],
[bigint],
"view"
>;
getFunction(
nameOrSignature: "approve"
): TypedContractMethod<
[spender: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction(
nameOrSignature: "balanceOf"
): TypedContractMethod<[account: AddressLike], [bigint], "view">;
getFunction(
nameOrSignature: "consumedReceipts"
): TypedContractMethod<[arg0: BytesLike], [boolean], "view">;
getFunction(
nameOrSignature: "decimals"
): TypedContractMethod<[], [bigint], "view">;
getFunction(
nameOrSignature: "getRoleAdmin"
): TypedContractMethod<[role: BytesLike], [string], "view">;
getFunction(
nameOrSignature: "grantRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "hasRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[boolean],
"view"
>;
getFunction(
nameOrSignature: "mintDigest"
): TypedContractMethod<
[provider: AddressLike, units: BigNumberish, receiptHash: BytesLike],
[string],
"view"
>;
getFunction(
nameOrSignature: "mintWithReceipt"
): TypedContractMethod<
[
provider: AddressLike,
units: BigNumberish,
receiptHash: BytesLike,
signature: BytesLike
],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "name"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "renounceRole"
): TypedContractMethod<
[role: BytesLike, callerConfirmation: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "revokeRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "supportsInterface"
): TypedContractMethod<[interfaceId: BytesLike], [boolean], "view">;
getFunction(
nameOrSignature: "symbol"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "totalSupply"
): TypedContractMethod<[], [bigint], "view">;
getFunction(
nameOrSignature: "transfer"
): TypedContractMethod<
[to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getFunction(
nameOrSignature: "transferFrom"
): TypedContractMethod<
[from: AddressLike, to: AddressLike, value: BigNumberish],
[boolean],
"nonpayable"
>;
getEvent(
key: "Approval"
): TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
getEvent(
key: "ReceiptConsumed"
): TypedContractEvent<
ReceiptConsumedEvent.InputTuple,
ReceiptConsumedEvent.OutputTuple,
ReceiptConsumedEvent.OutputObject
>;
getEvent(
key: "RoleAdminChanged"
): TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
getEvent(
key: "RoleGranted"
): TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
getEvent(
key: "RoleRevoked"
): TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
getEvent(
key: "Transfer"
): TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
filters: {
"Approval(address,address,uint256)": TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
Approval: TypedContractEvent<
ApprovalEvent.InputTuple,
ApprovalEvent.OutputTuple,
ApprovalEvent.OutputObject
>;
"ReceiptConsumed(bytes32,address,uint256,address)": TypedContractEvent<
ReceiptConsumedEvent.InputTuple,
ReceiptConsumedEvent.OutputTuple,
ReceiptConsumedEvent.OutputObject
>;
ReceiptConsumed: TypedContractEvent<
ReceiptConsumedEvent.InputTuple,
ReceiptConsumedEvent.OutputTuple,
ReceiptConsumedEvent.OutputObject
>;
"RoleAdminChanged(bytes32,bytes32,bytes32)": TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
RoleAdminChanged: TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
"RoleGranted(bytes32,address,address)": TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
RoleGranted: TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
"RoleRevoked(bytes32,address,address)": TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
RoleRevoked: TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
"Transfer(address,address,uint256)": TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
Transfer: TypedContractEvent<
TransferEvent.InputTuple,
TransferEvent.OutputTuple,
TransferEvent.OutputObject
>;
};
}

View File

@@ -0,0 +1,512 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumberish,
BytesLike,
FunctionFragment,
Result,
Interface,
EventFragment,
AddressLike,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedLogDescription,
TypedListener,
TypedContractMethod,
} from "../common";
export declare namespace AITokenRegistry {
export type ProviderInfoStruct = {
active: boolean;
collateral: BigNumberish;
};
export type ProviderInfoStructOutput = [
active: boolean,
collateral: bigint
] & { active: boolean; collateral: bigint };
}
export interface AITokenRegistryInterface extends Interface {
getFunction(
nameOrSignature:
| "COORDINATOR_ROLE"
| "DEFAULT_ADMIN_ROLE"
| "getRoleAdmin"
| "grantRole"
| "hasRole"
| "providerInfo"
| "providers"
| "registerProvider"
| "renounceRole"
| "revokeRole"
| "supportsInterface"
| "updateProvider"
): FunctionFragment;
getEvent(
nameOrSignatureOrTopic:
| "ProviderRegistered"
| "ProviderUpdated"
| "RoleAdminChanged"
| "RoleGranted"
| "RoleRevoked"
): EventFragment;
encodeFunctionData(
functionFragment: "COORDINATOR_ROLE",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "DEFAULT_ADMIN_ROLE",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "getRoleAdmin",
values: [BytesLike]
): string;
encodeFunctionData(
functionFragment: "grantRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "hasRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "providerInfo",
values: [AddressLike]
): string;
encodeFunctionData(
functionFragment: "providers",
values: [AddressLike]
): string;
encodeFunctionData(
functionFragment: "registerProvider",
values: [AddressLike, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "renounceRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "revokeRole",
values: [BytesLike, AddressLike]
): string;
encodeFunctionData(
functionFragment: "supportsInterface",
values: [BytesLike]
): string;
encodeFunctionData(
functionFragment: "updateProvider",
values: [AddressLike, boolean, BigNumberish]
): string;
decodeFunctionResult(
functionFragment: "COORDINATOR_ROLE",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "DEFAULT_ADMIN_ROLE",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "getRoleAdmin",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "grantRole", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "hasRole", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "providerInfo",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "providers", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "registerProvider",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "renounceRole",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "revokeRole", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "supportsInterface",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "updateProvider",
data: BytesLike
): Result;
}
export namespace ProviderRegisteredEvent {
export type InputTuple = [provider: AddressLike, collateral: BigNumberish];
export type OutputTuple = [provider: string, collateral: bigint];
export interface OutputObject {
provider: string;
collateral: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace ProviderUpdatedEvent {
export type InputTuple = [
provider: AddressLike,
active: boolean,
collateral: BigNumberish
];
export type OutputTuple = [
provider: string,
active: boolean,
collateral: bigint
];
export interface OutputObject {
provider: string;
active: boolean;
collateral: bigint;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleAdminChangedEvent {
export type InputTuple = [
role: BytesLike,
previousAdminRole: BytesLike,
newAdminRole: BytesLike
];
export type OutputTuple = [
role: string,
previousAdminRole: string,
newAdminRole: string
];
export interface OutputObject {
role: string;
previousAdminRole: string;
newAdminRole: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleGrantedEvent {
export type InputTuple = [
role: BytesLike,
account: AddressLike,
sender: AddressLike
];
export type OutputTuple = [role: string, account: string, sender: string];
export interface OutputObject {
role: string;
account: string;
sender: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export namespace RoleRevokedEvent {
export type InputTuple = [
role: BytesLike,
account: AddressLike,
sender: AddressLike
];
export type OutputTuple = [role: string, account: string, sender: string];
export interface OutputObject {
role: string;
account: string;
sender: string;
}
export type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
export type Filter = TypedDeferredTopicFilter<Event>;
export type Log = TypedEventLog<Event>;
export type LogDescription = TypedLogDescription<Event>;
}
export interface AITokenRegistry extends BaseContract {
connect(runner?: ContractRunner | null): AITokenRegistry;
waitForDeployment(): Promise<this>;
interface: AITokenRegistryInterface;
queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;
COORDINATOR_ROLE: TypedContractMethod<[], [string], "view">;
DEFAULT_ADMIN_ROLE: TypedContractMethod<[], [string], "view">;
getRoleAdmin: TypedContractMethod<[role: BytesLike], [string], "view">;
grantRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
hasRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[boolean],
"view"
>;
providerInfo: TypedContractMethod<
[provider: AddressLike],
[AITokenRegistry.ProviderInfoStructOutput],
"view"
>;
providers: TypedContractMethod<
[arg0: AddressLike],
[[boolean, bigint] & { active: boolean; collateral: bigint }],
"view"
>;
registerProvider: TypedContractMethod<
[provider: AddressLike, collateral: BigNumberish],
[void],
"nonpayable"
>;
renounceRole: TypedContractMethod<
[role: BytesLike, callerConfirmation: AddressLike],
[void],
"nonpayable"
>;
revokeRole: TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
supportsInterface: TypedContractMethod<
[interfaceId: BytesLike],
[boolean],
"view"
>;
updateProvider: TypedContractMethod<
[provider: AddressLike, active: boolean, collateral: BigNumberish],
[void],
"nonpayable"
>;
getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;
getFunction(
nameOrSignature: "COORDINATOR_ROLE"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "DEFAULT_ADMIN_ROLE"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "getRoleAdmin"
): TypedContractMethod<[role: BytesLike], [string], "view">;
getFunction(
nameOrSignature: "grantRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "hasRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[boolean],
"view"
>;
getFunction(
nameOrSignature: "providerInfo"
): TypedContractMethod<
[provider: AddressLike],
[AITokenRegistry.ProviderInfoStructOutput],
"view"
>;
getFunction(
nameOrSignature: "providers"
): TypedContractMethod<
[arg0: AddressLike],
[[boolean, bigint] & { active: boolean; collateral: bigint }],
"view"
>;
getFunction(
nameOrSignature: "registerProvider"
): TypedContractMethod<
[provider: AddressLike, collateral: BigNumberish],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "renounceRole"
): TypedContractMethod<
[role: BytesLike, callerConfirmation: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "revokeRole"
): TypedContractMethod<
[role: BytesLike, account: AddressLike],
[void],
"nonpayable"
>;
getFunction(
nameOrSignature: "supportsInterface"
): TypedContractMethod<[interfaceId: BytesLike], [boolean], "view">;
getFunction(
nameOrSignature: "updateProvider"
): TypedContractMethod<
[provider: AddressLike, active: boolean, collateral: BigNumberish],
[void],
"nonpayable"
>;
getEvent(
key: "ProviderRegistered"
): TypedContractEvent<
ProviderRegisteredEvent.InputTuple,
ProviderRegisteredEvent.OutputTuple,
ProviderRegisteredEvent.OutputObject
>;
getEvent(
key: "ProviderUpdated"
): TypedContractEvent<
ProviderUpdatedEvent.InputTuple,
ProviderUpdatedEvent.OutputTuple,
ProviderUpdatedEvent.OutputObject
>;
getEvent(
key: "RoleAdminChanged"
): TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
getEvent(
key: "RoleGranted"
): TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
getEvent(
key: "RoleRevoked"
): TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
filters: {
"ProviderRegistered(address,uint256)": TypedContractEvent<
ProviderRegisteredEvent.InputTuple,
ProviderRegisteredEvent.OutputTuple,
ProviderRegisteredEvent.OutputObject
>;
ProviderRegistered: TypedContractEvent<
ProviderRegisteredEvent.InputTuple,
ProviderRegisteredEvent.OutputTuple,
ProviderRegisteredEvent.OutputObject
>;
"ProviderUpdated(address,bool,uint256)": TypedContractEvent<
ProviderUpdatedEvent.InputTuple,
ProviderUpdatedEvent.OutputTuple,
ProviderUpdatedEvent.OutputObject
>;
ProviderUpdated: TypedContractEvent<
ProviderUpdatedEvent.InputTuple,
ProviderUpdatedEvent.OutputTuple,
ProviderUpdatedEvent.OutputObject
>;
"RoleAdminChanged(bytes32,bytes32,bytes32)": TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
RoleAdminChanged: TypedContractEvent<
RoleAdminChangedEvent.InputTuple,
RoleAdminChangedEvent.OutputTuple,
RoleAdminChangedEvent.OutputObject
>;
"RoleGranted(bytes32,address,address)": TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
RoleGranted: TypedContractEvent<
RoleGrantedEvent.InputTuple,
RoleGrantedEvent.OutputTuple,
RoleGrantedEvent.OutputObject
>;
"RoleRevoked(bytes32,address,address)": TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
RoleRevoked: TypedContractEvent<
RoleRevokedEvent.InputTuple,
RoleRevokedEvent.OutputTuple,
RoleRevokedEvent.OutputObject
>;
};
}

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export type { AIToken } from "./AIToken";
export type { AITokenRegistry } from "./AITokenRegistry";

View File

@@ -0,0 +1,250 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
AccessControl,
AccessControlInterface,
} from "../../../../@openzeppelin/contracts/access/AccessControl";
const _abi = [
{
inputs: [],
name: "AccessControlBadConfirmation",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
{
internalType: "bytes32",
name: "neededRole",
type: "bytes32",
},
],
name: "AccessControlUnauthorizedAccount",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
indexed: true,
internalType: "bytes32",
name: "previousAdminRole",
type: "bytes32",
},
{
indexed: true,
internalType: "bytes32",
name: "newAdminRole",
type: "bytes32",
},
],
name: "RoleAdminChanged",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
indexed: true,
internalType: "address",
name: "account",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "sender",
type: "address",
},
],
name: "RoleGranted",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
indexed: true,
internalType: "address",
name: "account",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "sender",
type: "address",
},
],
name: "RoleRevoked",
type: "event",
},
{
inputs: [],
name: "DEFAULT_ADMIN_ROLE",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
],
name: "getRoleAdmin",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "grantRole",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "hasRole",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "callerConfirmation",
type: "address",
},
],
name: "renounceRole",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "revokeRole",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "bytes4",
name: "interfaceId",
type: "bytes4",
},
],
name: "supportsInterface",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
] as const;
export class AccessControl__factory {
static readonly abi = _abi;
static createInterface(): AccessControlInterface {
return new Interface(_abi) as AccessControlInterface;
}
static connect(
address: string,
runner?: ContractRunner | null
): AccessControl {
return new Contract(address, _abi, runner) as unknown as AccessControl;
}
}

View File

@@ -0,0 +1,218 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
IAccessControl,
IAccessControlInterface,
} from "../../../../@openzeppelin/contracts/access/IAccessControl";
const _abi = [
{
inputs: [],
name: "AccessControlBadConfirmation",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
{
internalType: "bytes32",
name: "neededRole",
type: "bytes32",
},
],
name: "AccessControlUnauthorizedAccount",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
indexed: true,
internalType: "bytes32",
name: "previousAdminRole",
type: "bytes32",
},
{
indexed: true,
internalType: "bytes32",
name: "newAdminRole",
type: "bytes32",
},
],
name: "RoleAdminChanged",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
indexed: true,
internalType: "address",
name: "account",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "sender",
type: "address",
},
],
name: "RoleGranted",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
indexed: true,
internalType: "address",
name: "account",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "sender",
type: "address",
},
],
name: "RoleRevoked",
type: "event",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
],
name: "getRoleAdmin",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "grantRole",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "hasRole",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "callerConfirmation",
type: "address",
},
],
name: "renounceRole",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "revokeRole",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
] as const;
export class IAccessControl__factory {
static readonly abi = _abi;
static createInterface(): IAccessControlInterface {
return new Interface(_abi) as IAccessControlInterface;
}
static connect(
address: string,
runner?: ContractRunner | null
): IAccessControl {
return new Contract(address, _abi, runner) as unknown as IAccessControl;
}
}

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export { AccessControl__factory } from "./AccessControl__factory";
export { IAccessControl__factory } from "./IAccessControl__factory";

View File

@@ -0,0 +1,7 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export * as access from "./access";
export * as interfaces from "./interfaces";
export * as token from "./token";
export * as utils from "./utils";

View File

@@ -0,0 +1,127 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
IERC1155Errors,
IERC1155ErrorsInterface,
} from "../../../../../@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors";
const _abi = [
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
{
internalType: "uint256",
name: "balance",
type: "uint256",
},
{
internalType: "uint256",
name: "needed",
type: "uint256",
},
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "ERC1155InsufficientBalance",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "approver",
type: "address",
},
],
name: "ERC1155InvalidApprover",
type: "error",
},
{
inputs: [
{
internalType: "uint256",
name: "idsLength",
type: "uint256",
},
{
internalType: "uint256",
name: "valuesLength",
type: "uint256",
},
],
name: "ERC1155InvalidArrayLength",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "operator",
type: "address",
},
],
name: "ERC1155InvalidOperator",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "receiver",
type: "address",
},
],
name: "ERC1155InvalidReceiver",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
],
name: "ERC1155InvalidSender",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "operator",
type: "address",
},
{
internalType: "address",
name: "owner",
type: "address",
},
],
name: "ERC1155MissingApprovalForAll",
type: "error",
},
] as const;
export class IERC1155Errors__factory {
static readonly abi = _abi;
static createInterface(): IERC1155ErrorsInterface {
return new Interface(_abi) as IERC1155ErrorsInterface;
}
static connect(
address: string,
runner?: ContractRunner | null
): IERC1155Errors {
return new Contract(address, _abi, runner) as unknown as IERC1155Errors;
}
}

View File

@@ -0,0 +1,111 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
IERC20Errors,
IERC20ErrorsInterface,
} from "../../../../../@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors";
const _abi = [
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
{
internalType: "uint256",
name: "allowance",
type: "uint256",
},
{
internalType: "uint256",
name: "needed",
type: "uint256",
},
],
name: "ERC20InsufficientAllowance",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
{
internalType: "uint256",
name: "balance",
type: "uint256",
},
{
internalType: "uint256",
name: "needed",
type: "uint256",
},
],
name: "ERC20InsufficientBalance",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "approver",
type: "address",
},
],
name: "ERC20InvalidApprover",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "receiver",
type: "address",
},
],
name: "ERC20InvalidReceiver",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
],
name: "ERC20InvalidSender",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "ERC20InvalidSpender",
type: "error",
},
] as const;
export class IERC20Errors__factory {
static readonly abi = _abi;
static createInterface(): IERC20ErrorsInterface {
return new Interface(_abi) as IERC20ErrorsInterface;
}
static connect(
address: string,
runner?: ContractRunner | null
): IERC20Errors {
return new Contract(address, _abi, runner) as unknown as IERC20Errors;
}
}

View File

@@ -0,0 +1,128 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
IERC721Errors,
IERC721ErrorsInterface,
} from "../../../../../@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors";
const _abi = [
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
{
internalType: "address",
name: "owner",
type: "address",
},
],
name: "ERC721IncorrectOwner",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "operator",
type: "address",
},
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "ERC721InsufficientApproval",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "approver",
type: "address",
},
],
name: "ERC721InvalidApprover",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "operator",
type: "address",
},
],
name: "ERC721InvalidOperator",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
],
name: "ERC721InvalidOwner",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "receiver",
type: "address",
},
],
name: "ERC721InvalidReceiver",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
],
name: "ERC721InvalidSender",
type: "error",
},
{
inputs: [
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "ERC721NonexistentToken",
type: "error",
},
] as const;
export class IERC721Errors__factory {
static readonly abi = _abi;
static createInterface(): IERC721ErrorsInterface {
return new Interface(_abi) as IERC721ErrorsInterface;
}
static connect(
address: string,
runner?: ContractRunner | null
): IERC721Errors {
return new Contract(address, _abi, runner) as unknown as IERC721Errors;
}
}

View File

@@ -0,0 +1,6 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export { IERC1155Errors__factory } from "./IERC1155Errors__factory";
export { IERC20Errors__factory } from "./IERC20Errors__factory";
export { IERC721Errors__factory } from "./IERC721Errors__factory";

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export * as draftIerc6093Sol from "./draft-IERC6093.sol";

View File

@@ -0,0 +1,330 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
ERC20,
ERC20Interface,
} from "../../../../../@openzeppelin/contracts/token/ERC20/ERC20";
const _abi = [
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
{
internalType: "uint256",
name: "allowance",
type: "uint256",
},
{
internalType: "uint256",
name: "needed",
type: "uint256",
},
],
name: "ERC20InsufficientAllowance",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
{
internalType: "uint256",
name: "balance",
type: "uint256",
},
{
internalType: "uint256",
name: "needed",
type: "uint256",
},
],
name: "ERC20InsufficientBalance",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "approver",
type: "address",
},
],
name: "ERC20InvalidApprover",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "receiver",
type: "address",
},
],
name: "ERC20InvalidReceiver",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
],
name: "ERC20InvalidSender",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "ERC20InvalidSpender",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "owner",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "spender",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "Approval",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "from",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "to",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "Transfer",
type: "event",
},
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "allowance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "approve",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "balanceOf",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "decimals",
outputs: [
{
internalType: "uint8",
name: "",
type: "uint8",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "name",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "symbol",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "totalSupply",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "transfer",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address",
},
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "transferFrom",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
] as const;
export class ERC20__factory {
static readonly abi = _abi;
static createInterface(): ERC20Interface {
return new Interface(_abi) as ERC20Interface;
}
static connect(address: string, runner?: ContractRunner | null): ERC20 {
return new Contract(address, _abi, runner) as unknown as ERC20;
}
}

View File

@@ -0,0 +1,205 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
IERC20,
IERC20Interface,
} from "../../../../../@openzeppelin/contracts/token/ERC20/IERC20";
const _abi = [
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "owner",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "spender",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "Approval",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "from",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "to",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "Transfer",
type: "event",
},
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "allowance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "approve",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "balanceOf",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "totalSupply",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "transfer",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address",
},
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "transferFrom",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
] as const;
export class IERC20__factory {
static readonly abi = _abi;
static createInterface(): IERC20Interface {
return new Interface(_abi) as IERC20Interface;
}
static connect(address: string, runner?: ContractRunner | null): IERC20 {
return new Contract(address, _abi, runner) as unknown as IERC20;
}
}

View File

@@ -0,0 +1,247 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
IERC20Metadata,
IERC20MetadataInterface,
} from "../../../../../../@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata";
const _abi = [
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "owner",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "spender",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "Approval",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "from",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "to",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "Transfer",
type: "event",
},
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "allowance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "approve",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "balanceOf",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "decimals",
outputs: [
{
internalType: "uint8",
name: "",
type: "uint8",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "name",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "symbol",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "totalSupply",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "transfer",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address",
},
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "transferFrom",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
] as const;
export class IERC20Metadata__factory {
static readonly abi = _abi;
static createInterface(): IERC20MetadataInterface {
return new Interface(_abi) as IERC20MetadataInterface;
}
static connect(
address: string,
runner?: ContractRunner | null
): IERC20Metadata {
return new Contract(address, _abi, runner) as unknown as IERC20Metadata;
}
}

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export { IERC20Metadata__factory } from "./IERC20Metadata__factory";

View File

@@ -0,0 +1,6 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export * as extensions from "./extensions";
export { ERC20__factory } from "./ERC20__factory";
export { IERC20__factory } from "./IERC20__factory";

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export * as erc20 from "./ERC20";

View File

@@ -0,0 +1,90 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import {
Contract,
ContractFactory,
ContractTransactionResponse,
Interface,
} from "ethers";
import type { Signer, ContractDeployTransaction, ContractRunner } from "ethers";
import type { NonPayableOverrides } from "../../../../common";
import type {
Strings,
StringsInterface,
} from "../../../../@openzeppelin/contracts/utils/Strings";
const _abi = [
{
inputs: [
{
internalType: "uint256",
name: "value",
type: "uint256",
},
{
internalType: "uint256",
name: "length",
type: "uint256",
},
],
name: "StringsInsufficientHexLength",
type: "error",
},
{
inputs: [],
name: "StringsInvalidAddressFormat",
type: "error",
},
{
inputs: [],
name: "StringsInvalidChar",
type: "error",
},
] as const;
const _bytecode =
"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d3fa6b95cf4f76e64227a9b2373ccb228efd9715fd7983e0646867999cceb9fb64736f6c63430008180033";
type StringsConstructorParams =
| [signer?: Signer]
| ConstructorParameters<typeof ContractFactory>;
const isSuperArgs = (
xs: StringsConstructorParams
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;
export class Strings__factory extends ContractFactory {
constructor(...args: StringsConstructorParams) {
if (isSuperArgs(args)) {
super(...args);
} else {
super(_abi, _bytecode, args[0]);
}
}
override getDeployTransaction(
overrides?: NonPayableOverrides & { from?: string }
): Promise<ContractDeployTransaction> {
return super.getDeployTransaction(overrides || {});
}
override deploy(overrides?: NonPayableOverrides & { from?: string }) {
return super.deploy(overrides || {}) as Promise<
Strings & {
deploymentTransaction(): ContractTransactionResponse;
}
>;
}
override connect(runner: ContractRunner | null): Strings__factory {
return super.connect(runner) as Strings__factory;
}
static readonly bytecode = _bytecode;
static readonly abi = _abi;
static createInterface(): StringsInterface {
return new Interface(_abi) as StringsInterface;
}
static connect(address: string, runner?: ContractRunner | null): Strings {
return new Contract(address, _abi, runner) as unknown as Strings;
}
}

View File

@@ -0,0 +1,91 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import {
Contract,
ContractFactory,
ContractTransactionResponse,
Interface,
} from "ethers";
import type { Signer, ContractDeployTransaction, ContractRunner } from "ethers";
import type { NonPayableOverrides } from "../../../../../common";
import type {
ECDSA,
ECDSAInterface,
} from "../../../../../@openzeppelin/contracts/utils/cryptography/ECDSA";
const _abi = [
{
inputs: [],
name: "ECDSAInvalidSignature",
type: "error",
},
{
inputs: [
{
internalType: "uint256",
name: "length",
type: "uint256",
},
],
name: "ECDSAInvalidSignatureLength",
type: "error",
},
{
inputs: [
{
internalType: "bytes32",
name: "s",
type: "bytes32",
},
],
name: "ECDSAInvalidSignatureS",
type: "error",
},
] as const;
const _bytecode =
"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220a02ae933cd95f2ee943a9a3e5cbf4c6b7a6f7cc463d2cb58fac8fce23a0ba09464736f6c63430008180033";
type ECDSAConstructorParams =
| [signer?: Signer]
| ConstructorParameters<typeof ContractFactory>;
const isSuperArgs = (
xs: ECDSAConstructorParams
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;
export class ECDSA__factory extends ContractFactory {
constructor(...args: ECDSAConstructorParams) {
if (isSuperArgs(args)) {
super(...args);
} else {
super(_abi, _bytecode, args[0]);
}
}
override getDeployTransaction(
overrides?: NonPayableOverrides & { from?: string }
): Promise<ContractDeployTransaction> {
return super.getDeployTransaction(overrides || {});
}
override deploy(overrides?: NonPayableOverrides & { from?: string }) {
return super.deploy(overrides || {}) as Promise<
ECDSA & {
deploymentTransaction(): ContractTransactionResponse;
}
>;
}
override connect(runner: ContractRunner | null): ECDSA__factory {
return super.connect(runner) as ECDSA__factory;
}
static readonly bytecode = _bytecode;
static readonly abi = _abi;
static createInterface(): ECDSAInterface {
return new Interface(_abi) as ECDSAInterface;
}
static connect(address: string, runner?: ContractRunner | null): ECDSA {
return new Contract(address, _abi, runner) as unknown as ECDSA;
}
}

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export { ECDSA__factory } from "./ECDSA__factory";

View File

@@ -0,0 +1,7 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export * as cryptography from "./cryptography";
export * as introspection from "./introspection";
export * as math from "./math";
export { Strings__factory } from "./Strings__factory";

View File

@@ -0,0 +1,41 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
ERC165,
ERC165Interface,
} from "../../../../../@openzeppelin/contracts/utils/introspection/ERC165";
const _abi = [
{
inputs: [
{
internalType: "bytes4",
name: "interfaceId",
type: "bytes4",
},
],
name: "supportsInterface",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
] as const;
export class ERC165__factory {
static readonly abi = _abi;
static createInterface(): ERC165Interface {
return new Interface(_abi) as ERC165Interface;
}
static connect(address: string, runner?: ContractRunner | null): ERC165 {
return new Contract(address, _abi, runner) as unknown as ERC165;
}
}

View File

@@ -0,0 +1,41 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Interface, type ContractRunner } from "ethers";
import type {
IERC165,
IERC165Interface,
} from "../../../../../@openzeppelin/contracts/utils/introspection/IERC165";
const _abi = [
{
inputs: [
{
internalType: "bytes4",
name: "interfaceId",
type: "bytes4",
},
],
name: "supportsInterface",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
] as const;
export class IERC165__factory {
static readonly abi = _abi;
static createInterface(): IERC165Interface {
return new Interface(_abi) as IERC165Interface;
}
static connect(address: string, runner?: ContractRunner | null): IERC165 {
return new Contract(address, _abi, runner) as unknown as IERC165;
}
}

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export { ERC165__factory } from "./ERC165__factory";
export { IERC165__factory } from "./IERC165__factory";

View File

@@ -0,0 +1,118 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import {
Contract,
ContractFactory,
ContractTransactionResponse,
Interface,
} from "ethers";
import type { Signer, ContractDeployTransaction, ContractRunner } from "ethers";
import type { NonPayableOverrides } from "../../../../../common";
import type {
SafeCast,
SafeCastInterface,
} from "../../../../../@openzeppelin/contracts/utils/math/SafeCast";
const _abi = [
{
inputs: [
{
internalType: "uint8",
name: "bits",
type: "uint8",
},
{
internalType: "int256",
name: "value",
type: "int256",
},
],
name: "SafeCastOverflowedIntDowncast",
type: "error",
},
{
inputs: [
{
internalType: "int256",
name: "value",
type: "int256",
},
],
name: "SafeCastOverflowedIntToUint",
type: "error",
},
{
inputs: [
{
internalType: "uint8",
name: "bits",
type: "uint8",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "SafeCastOverflowedUintDowncast",
type: "error",
},
{
inputs: [
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "SafeCastOverflowedUintToInt",
type: "error",
},
] as const;
const _bytecode =
"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212201c97bba8d553a67561101942b2a9afa3628667de55efed8df898d3aab783793c64736f6c63430008180033";
type SafeCastConstructorParams =
| [signer?: Signer]
| ConstructorParameters<typeof ContractFactory>;
const isSuperArgs = (
xs: SafeCastConstructorParams
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;
export class SafeCast__factory extends ContractFactory {
constructor(...args: SafeCastConstructorParams) {
if (isSuperArgs(args)) {
super(...args);
} else {
super(_abi, _bytecode, args[0]);
}
}
override getDeployTransaction(
overrides?: NonPayableOverrides & { from?: string }
): Promise<ContractDeployTransaction> {
return super.getDeployTransaction(overrides || {});
}
override deploy(overrides?: NonPayableOverrides & { from?: string }) {
return super.deploy(overrides || {}) as Promise<
SafeCast & {
deploymentTransaction(): ContractTransactionResponse;
}
>;
}
override connect(runner: ContractRunner | null): SafeCast__factory {
return super.connect(runner) as SafeCast__factory;
}
static readonly bytecode = _bytecode;
static readonly abi = _abi;
static createInterface(): SafeCastInterface {
return new Interface(_abi) as SafeCastInterface;
}
static connect(address: string, runner?: ContractRunner | null): SafeCast {
return new Contract(address, _abi, runner) as unknown as SafeCast;
}
}

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export { SafeCast__factory } from "./SafeCast__factory";

View File

@@ -0,0 +1,4 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export * as contracts from "./contracts";

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export { AIToken__factory } from "./AIToken__factory";
export { AITokenRegistry__factory } from "./AITokenRegistry__factory";

View File

@@ -0,0 +1,5 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export * as openzeppelin from "./@openzeppelin";
export * as contracts from "./contracts";

View File

@@ -0,0 +1,315 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { ethers } from "ethers";
import {
DeployContractOptions,
FactoryOptions,
HardhatEthersHelpers as HardhatEthersHelpersBase,
} from "@nomicfoundation/hardhat-ethers/types";
import * as Contracts from ".";
declare module "hardhat/types/runtime" {
interface HardhatEthersHelpers extends HardhatEthersHelpersBase {
getContractFactory(
name: "AccessControl",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.AccessControl__factory>;
getContractFactory(
name: "IAccessControl",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.IAccessControl__factory>;
getContractFactory(
name: "IERC1155Errors",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.IERC1155Errors__factory>;
getContractFactory(
name: "IERC20Errors",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.IERC20Errors__factory>;
getContractFactory(
name: "IERC721Errors",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.IERC721Errors__factory>;
getContractFactory(
name: "ERC20",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.ERC20__factory>;
getContractFactory(
name: "IERC20Metadata",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.IERC20Metadata__factory>;
getContractFactory(
name: "IERC20",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.IERC20__factory>;
getContractFactory(
name: "ECDSA",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.ECDSA__factory>;
getContractFactory(
name: "ERC165",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.ERC165__factory>;
getContractFactory(
name: "IERC165",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.IERC165__factory>;
getContractFactory(
name: "SafeCast",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.SafeCast__factory>;
getContractFactory(
name: "Strings",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.Strings__factory>;
getContractFactory(
name: "AIToken",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.AIToken__factory>;
getContractFactory(
name: "AITokenRegistry",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.AITokenRegistry__factory>;
getContractAt(
name: "AccessControl",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.AccessControl>;
getContractAt(
name: "IAccessControl",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.IAccessControl>;
getContractAt(
name: "IERC1155Errors",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.IERC1155Errors>;
getContractAt(
name: "IERC20Errors",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.IERC20Errors>;
getContractAt(
name: "IERC721Errors",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.IERC721Errors>;
getContractAt(
name: "ERC20",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.ERC20>;
getContractAt(
name: "IERC20Metadata",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.IERC20Metadata>;
getContractAt(
name: "IERC20",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.IERC20>;
getContractAt(
name: "ECDSA",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.ECDSA>;
getContractAt(
name: "ERC165",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.ERC165>;
getContractAt(
name: "IERC165",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.IERC165>;
getContractAt(
name: "SafeCast",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.SafeCast>;
getContractAt(
name: "Strings",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.Strings>;
getContractAt(
name: "AIToken",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.AIToken>;
getContractAt(
name: "AITokenRegistry",
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<Contracts.AITokenRegistry>;
deployContract(
name: "AccessControl",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.AccessControl>;
deployContract(
name: "IAccessControl",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IAccessControl>;
deployContract(
name: "IERC1155Errors",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC1155Errors>;
deployContract(
name: "IERC20Errors",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC20Errors>;
deployContract(
name: "IERC721Errors",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC721Errors>;
deployContract(
name: "ERC20",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.ERC20>;
deployContract(
name: "IERC20Metadata",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC20Metadata>;
deployContract(
name: "IERC20",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC20>;
deployContract(
name: "ECDSA",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.ECDSA>;
deployContract(
name: "ERC165",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.ERC165>;
deployContract(
name: "IERC165",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC165>;
deployContract(
name: "SafeCast",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.SafeCast>;
deployContract(
name: "Strings",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.Strings>;
deployContract(
name: "AIToken",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.AIToken>;
deployContract(
name: "AITokenRegistry",
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.AITokenRegistry>;
deployContract(
name: "AccessControl",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.AccessControl>;
deployContract(
name: "IAccessControl",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IAccessControl>;
deployContract(
name: "IERC1155Errors",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC1155Errors>;
deployContract(
name: "IERC20Errors",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC20Errors>;
deployContract(
name: "IERC721Errors",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC721Errors>;
deployContract(
name: "ERC20",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.ERC20>;
deployContract(
name: "IERC20Metadata",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC20Metadata>;
deployContract(
name: "IERC20",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC20>;
deployContract(
name: "ECDSA",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.ECDSA>;
deployContract(
name: "ERC165",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.ERC165>;
deployContract(
name: "IERC165",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.IERC165>;
deployContract(
name: "SafeCast",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.SafeCast>;
deployContract(
name: "Strings",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.Strings>;
deployContract(
name: "AIToken",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.AIToken>;
deployContract(
name: "AITokenRegistry",
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<Contracts.AITokenRegistry>;
// default types
getContractFactory(
name: string,
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<ethers.ContractFactory>;
getContractFactory(
abi: any[],
bytecode: ethers.BytesLike,
signer?: ethers.Signer
): Promise<ethers.ContractFactory>;
getContractAt(
nameOrAbi: string | any[],
address: string | ethers.Addressable,
signer?: ethers.Signer
): Promise<ethers.Contract>;
deployContract(
name: string,
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<ethers.Contract>;
deployContract(
name: string,
args: any[],
signerOrOptions?: ethers.Signer | DeployContractOptions
): Promise<ethers.Contract>;
}
}

View File

@@ -0,0 +1,38 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type * as openzeppelin from "./@openzeppelin";
export type { openzeppelin };
import type * as contracts from "./contracts";
export type { contracts };
export * as factories from "./factories";
export type { AccessControl } from "./@openzeppelin/contracts/access/AccessControl";
export { AccessControl__factory } from "./factories/@openzeppelin/contracts/access/AccessControl__factory";
export type { IAccessControl } from "./@openzeppelin/contracts/access/IAccessControl";
export { IAccessControl__factory } from "./factories/@openzeppelin/contracts/access/IAccessControl__factory";
export type { IERC1155Errors } from "./@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors";
export { IERC1155Errors__factory } from "./factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors__factory";
export type { IERC20Errors } from "./@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors";
export { IERC20Errors__factory } from "./factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors__factory";
export type { IERC721Errors } from "./@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors";
export { IERC721Errors__factory } from "./factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors__factory";
export type { ERC20 } from "./@openzeppelin/contracts/token/ERC20/ERC20";
export { ERC20__factory } from "./factories/@openzeppelin/contracts/token/ERC20/ERC20__factory";
export type { IERC20Metadata } from "./@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata";
export { IERC20Metadata__factory } from "./factories/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata__factory";
export type { IERC20 } from "./@openzeppelin/contracts/token/ERC20/IERC20";
export { IERC20__factory } from "./factories/@openzeppelin/contracts/token/ERC20/IERC20__factory";
export type { ECDSA } from "./@openzeppelin/contracts/utils/cryptography/ECDSA";
export { ECDSA__factory } from "./factories/@openzeppelin/contracts/utils/cryptography/ECDSA__factory";
export type { ERC165 } from "./@openzeppelin/contracts/utils/introspection/ERC165";
export { ERC165__factory } from "./factories/@openzeppelin/contracts/utils/introspection/ERC165__factory";
export type { IERC165 } from "./@openzeppelin/contracts/utils/introspection/IERC165";
export { IERC165__factory } from "./factories/@openzeppelin/contracts/utils/introspection/IERC165__factory";
export type { SafeCast } from "./@openzeppelin/contracts/utils/math/SafeCast";
export { SafeCast__factory } from "./factories/@openzeppelin/contracts/utils/math/SafeCast__factory";
export type { Strings } from "./@openzeppelin/contracts/utils/Strings";
export { Strings__factory } from "./factories/@openzeppelin/contracts/utils/Strings__factory";
export type { AIToken } from "./contracts/AIToken";
export { AIToken__factory } from "./factories/contracts/AIToken__factory";
export type { AITokenRegistry } from "./contracts/AITokenRegistry";
export { AITokenRegistry__factory } from "./factories/contracts/AITokenRegistry__factory";

1866
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -147,7 +147,7 @@ dev = [
"black==24.3.0",
"isort==8.0.1",
"ruff==0.15.5",
"mypy==1.8.0",
"mypy>=1.19.1,<2.0.0",
"bandit==1.7.5",
"types-requests==2.31.0",
"types-setuptools==69.0.0",

View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Clean up failed deployment and prepare for redeployment
echo "🧹 Cleaning up failed deployment..."
echo "=================================="
# Stop any running services
echo "Stopping services..."
ssh ns3-root "systemctl stop blockchain-node blockchain-rpc nginx 2>/dev/null || true"
# Remove old directories
echo "Removing old directories..."
ssh ns3-root "rm -rf /opt/blockchain-node /opt/blockchain-node-src /opt/blockchain-explorer 2>/dev/null || true"
# Remove systemd services
echo "Removing systemd services..."
ssh ns3-root "systemctl disable blockchain-node blockchain-rpc blockchain-explorer 2>/dev/null || true"
ssh ns3-root "rm -f /etc/systemd/system/blockchain-node.service /etc/systemd/system/blockchain-rpc.service /etc/systemd/system/blockchain-explorer.service 2>/dev/null || true"
ssh ns3-root "systemctl daemon-reload"
echo "✅ Cleanup complete!"
echo ""
echo "You can now run: ./scripts/deploy/deploy-all-remote.sh"

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env python3
"""
Deploy AITBC services to incus container
"""
import subprocess
import time
import sys
def run_command(cmd, container=None):
"""Run command locally or in container"""
if container:
cmd = f"incus exec {container} -- {cmd}"
print(f"Running: {cmd}")
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
print(f"Error: {result.stderr}")
return False
return True
def deploy_to_container():
container = "aitbc"
container_ip = "10.1.223.93"
print("🚀 Deploying AITBC services to container...")
# Stop local services
print("\n📋 Stopping local services...")
subprocess.run("sudo fuser -k 8000/tcp 2>/dev/null || true", shell=True)
subprocess.run("sudo fuser -k 9080/tcp 2>/dev/null || true", shell=True)
subprocess.run("pkill -f 'marketplace-ui' 2>/dev/null || true", shell=True)
subprocess.run("pkill -f 'trade-exchange' 2>/dev/null || true", shell=True)
# Copy project to container
print("\n📁 Copying project to container...")
subprocess.run(f"incus file push -r /home/oib/windsurf/aitbc {container}/home/oib/", shell=True)
# Setup Python environment in container
print("\n🐍 Setting up Python environment...")
run_command("cd /home/oib/aitbc && python3 -m venv .venv", container)
run_command("cd /home/oib/aitbc && source .venv/bin/activate && pip install fastapi uvicorn httpx sqlmodel", container)
# Install dependencies
print("\n📦 Installing dependencies...")
run_command("cd /home/oib/aitbc/apps/coordinator-api && source ../../.venv/bin/activate && pip install -e .", container)
run_command("cd /home/oib/aitbc/apps/blockchain-node && source ../../.venv/bin/activate && pip install -e .", container)
# Create startup script
print("\n🔧 Creating startup script...")
startup_script = """#!/bin/bash
cd /home/oib/aitbc
# Start blockchain node
echo "Starting blockchain node..."
cd apps/blockchain-node
source ../../.venv/bin/activate
python -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 9080 &
NODE_PID=$!
# Start coordinator API
echo "Starting coordinator API..."
cd ../coordinator-api
source ../../.venv/bin/activate
python -m uvicorn src.app.main:app --host 0.0.0.0 --port 8000 &
COORD_PID=$!
# Start marketplace UI
echo "Starting marketplace UI..."
cd ../marketplace-ui
python server.py --port 3001 &
MARKET_PID=$!
# Start trade exchange
echo "Starting trade exchange..."
cd ../trade-exchange
python server.py --port 3002 &
EXCHANGE_PID=$!
echo "Services started!"
echo "Blockchain: http://10.1.223.93:9080"
echo "API: http://10.1.223.93:8000"
echo "Marketplace: http://10.1.223.93:3001"
echo "Exchange: http://10.1.223.93:3002"
# Wait for services
wait $NODE_PID $COORD_PID $MARKET_PID $EXCHANGE_PID
"""
# Write startup script to container
with open('/tmp/start_aitbc.sh', 'w') as f:
f.write(startup_script)
subprocess.run("incus file push /tmp/start_aitbc.sh aitbc/home/oib/", shell=True)
run_command("chmod +x /home/oib/start_aitbc.sh", container)
# Start services
print("\n🚀 Starting AITBC services...")
run_command("/home/oib/start_aitbc.sh", container)
print(f"\n✅ Services deployed to container!")
print(f"\n📋 Access URLs:")
print(f" 🌐 Container IP: {container_ip}")
print(f" 📊 Marketplace: http://{container_ip}:3001")
print(f" 💱 Trade Exchange: http://{container_ip}:3002")
print(f" 🔗 API: http://{container_ip}:8000")
print(f" ⛓️ Blockchain: http://{container_ip}:9080")
if __name__ == "__main__":
deploy_to_container()

View File

@@ -0,0 +1,56 @@
#!/bin/bash
# Deploy blockchain node and explorer by building directly on ns3
echo "🚀 AITBC Remote Deployment (Build on Server)"
echo "=========================================="
echo "This will build the blockchain node directly on ns3"
echo "to utilize the gigabit connection instead of uploading."
echo ""
# Copy deployment scripts to server
echo "Copying deployment scripts to ns3..."
scp scripts/deploy/deploy-blockchain-remote.sh ns3-root:/opt/
scp scripts/deploy/deploy-explorer-remote.sh ns3-root:/opt/
# Create directories on server first
echo "Creating directories on ns3..."
ssh ns3-root "mkdir -p /opt/blockchain-node-src /opt/blockchain-node"
# Copy blockchain source code to server (excluding data files)
echo "Copying blockchain source code to ns3..."
rsync -av --exclude='data/' --exclude='*.db' --exclude='__pycache__' --exclude='.venv' apps/blockchain-node/ ns3-root:/opt/blockchain-node-src/
# Execute blockchain deployment
echo ""
echo "Deploying blockchain node..."
ssh ns3-root "cd /opt && cp -r /opt/blockchain-node-src/* /opt/blockchain-node/ && cd /opt/blockchain-node && chmod +x ../deploy-blockchain-remote.sh && ../deploy-blockchain-remote.sh"
# Wait for blockchain to start
echo ""
echo "Waiting 10 seconds for blockchain node to start..."
sleep 10
# Execute explorer deployment on ns3
echo ""
echo "Deploying blockchain explorer..."
ssh ns3-root "cd /opt && ./deploy-explorer-remote.sh"
# Check services
echo ""
echo "Checking service status..."
ssh ns3-root "systemctl status blockchain-node blockchain-rpc nginx --no-pager | grep -E 'Active:|Main PID:'"
echo ""
echo "✅ Deployment complete!"
echo ""
echo "Services:"
echo " - Blockchain Node RPC: http://localhost:8082"
echo " - Blockchain Explorer: http://localhost:3000"
echo ""
echo "External access:"
echo " - Blockchain Node RPC: http://aitbc.keisanki.net:8082"
echo " - Blockchain Explorer: http://aitbc.keisanki.net:3000"
echo ""
echo "The blockchain node will start syncing automatically."
echo "The explorer connects to the local node and displays real-time data."

View File

@@ -0,0 +1,207 @@
#!/bin/bash
# Deploy blockchain node and explorer to incus container
set -e
echo "🚀 Deploying Blockchain Node and Explorer"
echo "========================================"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Copy blockchain node to container
print_status "Copying blockchain node to container..."
ssh ns3-root "rm -rf /opt/blockchain-node 2>/dev/null || true"
scp -r apps/blockchain-node ns3-root:/opt/
# Setup blockchain node in container
print_status "Setting up blockchain node..."
ssh ns3-root << 'EOF'
cd /opt/blockchain-node
# Create configuration
cat > .env << EOL
CHAIN_ID=ait-devnet
DB_PATH=./data/chain.db
RPC_BIND_HOST=0.0.0.0
RPC_BIND_PORT=8082
P2P_BIND_HOST=0.0.0.0
P2P_BIND_PORT=7070
PROPOSER_KEY=proposer_key_$(date +%s)
MINT_PER_UNIT=1000
COORDINATOR_RATIO=0.05
GOSSIP_BACKEND=memory
EOL
# Create data directory
mkdir -p data/devnet
# Setup Python environment
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .
# Generate genesis
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
python scripts/make_genesis.py --output data/devnet/genesis.json --force
EOF
# Create systemd service for blockchain node
print_status "Creating systemd service for blockchain node..."
ssh ns3-root << 'EOF'
cat > /etc/systemd/system/blockchain-node.service << EOL
[Unit]
Description=AITBC Blockchain Node
After=network.target
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
cat > /etc/systemd/system/blockchain-rpc.service << EOL
[Unit]
Description=AITBC Blockchain RPC API
After=blockchain-node.service
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
systemctl daemon-reload
systemctl enable blockchain-node blockchain-rpc
EOF
# Start blockchain node
print_status "Starting blockchain node..."
ssh ns3-root "systemctl start blockchain-node blockchain-rpc"
# Wait for node to start
print_status "Waiting for blockchain node to start..."
sleep 5
# Check status
print_status "Checking blockchain node status..."
ssh ns3-root "systemctl status blockchain-node blockchain-rpc --no-pager | grep -E 'Active:|Main PID:'"
# Copy explorer to container
print_status "Copying blockchain explorer to container..."
ssh ns3-root "rm -rf /opt/blockchain-explorer 2>/dev/null || true"
scp -r apps/blockchain-explorer ns3-root:/opt/
# Setup explorer in container
print_status "Setting up blockchain explorer..."
ssh ns3-root << 'EOF'
cd /opt/blockchain-explorer
# Create Python environment
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
EOF
# Create systemd service for explorer
print_status "Creating systemd service for blockchain explorer..."
ssh ns3-root << 'EOF'
cat > /etc/systemd/system/blockchain-explorer.service << EOL
[Unit]
Description=AITBC Blockchain Explorer
After=blockchain-rpc.service
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-explorer
Environment=PATH=/opt/blockchain-explorer/.venv/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/opt/blockchain-explorer/.venv/bin/python3 main.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
systemctl daemon-reload
systemctl enable blockchain-explorer
EOF
# Start explorer
print_status "Starting blockchain explorer..."
ssh ns3-root "systemctl start blockchain-explorer"
# Wait for explorer to start
print_status "Waiting for explorer to start..."
sleep 3
# Setup port forwarding
print_status "Setting up port forwarding..."
ssh ns3-root << 'EOF'
# Clear existing NAT rules
iptables -t nat -F PREROUTING 2>/dev/null || true
iptables -t nat -F POSTROUTING 2>/dev/null || true
# Add port forwarding for blockchain RPC
iptables -t nat -A PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE
# Add port forwarding for explorer
iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE
# Save rules
mkdir -p /etc/iptables
iptables-save > /etc/iptables/rules.v4
# Install iptables-persistent for persistence
apt-get update
apt-get install -y iptables-persistent
EOF
# Check all services
print_status "Checking all services..."
ssh ns3-root "systemctl status blockchain-node blockchain-rpc blockchain-explorer --no-pager | grep -E 'Active:|Main PID:'"
print_success "✅ Deployment complete!"
echo ""
echo "Services deployed:"
echo " - Blockchain Node RPC: http://192.168.100.10:8082"
echo " - Blockchain Explorer: http://192.168.100.10:3000"
echo ""
echo "External access:"
echo " - Blockchain Node RPC: http://aitbc.keisanki.net:8082"
echo " - Blockchain Explorer: http://aitbc.keisanki.net:3000"
echo ""
echo "The explorer is connected to the local blockchain node and will display"
echo "real-time blockchain data including blocks and transactions."

View File

@@ -0,0 +1,94 @@
#!/bin/bash
# Deploy blockchain explorer to incus container
set -e
echo "🔍 Deploying Blockchain Explorer"
echo "================================="
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Copy explorer to container
print_status "Copying blockchain explorer to container..."
ssh ns3-root "rm -rf /opt/blockchain-explorer 2>/dev/null || true"
scp -r apps/blockchain-explorer ns3-root:/opt/
# Setup explorer in container
print_status "Setting up blockchain explorer..."
ssh ns3-root << 'EOF'
cd /opt/blockchain-explorer
# Create Python environment
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
EOF
# Create systemd service for explorer
print_status "Creating systemd service for blockchain explorer..."
ssh ns3-root << 'EOF'
cat > /etc/systemd/system/blockchain-explorer.service << EOL
[Unit]
Description=AITBC Blockchain Explorer
After=blockchain-rpc.service
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-explorer
Environment=PATH=/opt/blockchain-explorer/.venv/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/opt/blockchain-explorer/.venv/bin/python3 main.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
systemctl daemon-reload
systemctl enable blockchain-explorer
EOF
# Start explorer
print_status "Starting blockchain explorer..."
ssh ns3-root "systemctl start blockchain-explorer"
# Wait for explorer to start
print_status "Waiting for explorer to start..."
sleep 3
# Setup port forwarding for explorer
print_status "Setting up port forwarding for explorer..."
ssh ns3-root << 'EOF'
# Add port forwarding for explorer
iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE
# Save rules
iptables-save > /etc/iptables/rules.v4
EOF
# Check status
print_status "Checking blockchain explorer status..."
ssh ns3-root "systemctl status blockchain-explorer --no-pager | grep -E 'Active:|Main PID:'"
print_success "✅ Blockchain explorer deployed!"
echo ""
echo "Explorer URL: http://192.168.100.10:3000"
echo "External URL: http://aitbc.keisanki.net:3000"
echo ""
echo "The explorer will automatically connect to the local blockchain node."
echo "You can view blocks, transactions, and chain statistics."

View File

@@ -0,0 +1,157 @@
#!/bin/bash
# Deploy blockchain node directly on ns3 server (build in place)
set -e
echo "🚀 Deploying Blockchain Node on ns3 (Build in Place)"
echo "====================================================="
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Check if we're on the right server
print_status "Checking server..."
if [ "$(hostname)" != "ns3" ] && [ "$(hostname)" != "aitbc" ]; then
print_warning "This script should be run on ns3 server"
echo "Please run: ssh ns3-root"
echo "Then: cd /opt && ./deploy-blockchain-remote.sh"
exit 1
fi
# Install dependencies if needed
print_status "Installing dependencies..."
apt-get update
apt-get install -y python3 python3-venv python3-pip git curl
# Create directory
print_status "Creating blockchain node directory..."
mkdir -p /opt/blockchain-node
cd /opt/blockchain-node
# Check if source code exists
if [ ! -d "src" ]; then
print_status "Source code not found in /opt/blockchain-node, copying from /opt/blockchain-node-src..."
if [ -d "/opt/blockchain-node-src" ]; then
cp -r /opt/blockchain-node-src/* .
else
print_warning "Source code not found. Please ensure it was copied properly."
exit 1
fi
fi
# Setup Python environment
print_status "Setting up Python environment..."
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .
# Create configuration with auto-sync
print_status "Creating configuration..."
cat > .env << EOL
CHAIN_ID=ait-devnet
DB_PATH=./data/chain.db
RPC_BIND_HOST=0.0.0.0
RPC_BIND_PORT=8082
P2P_BIND_HOST=0.0.0.0
P2P_BIND_PORT=7070
PROPOSER_KEY=proposer_key_$(date +%s)
MINT_PER_UNIT=1000
COORDINATOR_RATIO=0.05
GOSSIP_BACKEND=memory
EOL
# Create fresh data directory
print_status "Creating fresh data directory..."
rm -rf data
mkdir -p data/devnet
# Generate fresh genesis
print_status "Generating fresh genesis block..."
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
python scripts/make_genesis.py --output data/devnet/genesis.json --force
# Create systemd service for blockchain node
print_status "Creating systemd services..."
cat > /etc/systemd/system/blockchain-node.service << EOL
[Unit]
Description=AITBC Blockchain Node
After=network.target
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
cat > /etc/systemd/system/blockchain-rpc.service << EOL
[Unit]
Description=AITBC Blockchain RPC API
After=blockchain-node.service
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
# Enable and start services
print_status "Starting blockchain node..."
systemctl daemon-reload
systemctl enable blockchain-node blockchain-rpc
systemctl start blockchain-node blockchain-rpc
# Wait for services to start
print_status "Waiting for services to start..."
sleep 5
# Check status
print_status "Checking service status..."
systemctl status blockchain-node blockchain-rpc --no-pager | head -15
# Setup port forwarding if in container
if [ "$(hostname)" = "aitbc" ]; then
print_status "Setting up port forwarding..."
iptables -t nat -A PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE
iptables-save > /etc/iptables/rules.v4
fi
print_success "✅ Blockchain node deployed!"
echo ""
if [ "$(hostname)" = "aitbc" ]; then
echo "Node RPC: http://192.168.100.10:8082"
echo "External RPC: http://aitbc.keisanki.net:8082"
else
echo "Node RPC: http://95.216.198.140:8082"
echo "External RPC: http://aitbc.keisanki.net:8082"
fi
echo ""
echo "The node will automatically sync on startup."

View File

@@ -0,0 +1,139 @@
#!/bin/bash
# Deploy blockchain node and explorer to incus container
set -e
echo "🚀 Deploying Blockchain Node and Explorer"
echo "========================================"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Copy blockchain node to container
print_status "Copying blockchain node to container..."
ssh ns3-root "rm -rf /opt/blockchain-node 2>/dev/null || true"
scp -r apps/blockchain-node ns3-root:/opt/
# Setup blockchain node in container
print_status "Setting up blockchain node..."
ssh ns3-root << 'EOF'
cd /opt/blockchain-node
# Create configuration
cat > .env << EOL
CHAIN_ID=ait-devnet
DB_PATH=./data/chain.db
RPC_BIND_HOST=0.0.0.0
RPC_BIND_PORT=8082
P2P_BIND_HOST=0.0.0.0
P2P_BIND_PORT=7070
PROPOSER_KEY=proposer_key_$(date +%s)
MINT_PER_UNIT=1000
COORDINATOR_RATIO=0.05
GOSSIP_BACKEND=memory
EOL
# Create data directory
mkdir -p data/devnet
# Setup Python environment
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .
# Generate genesis
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
python scripts/make_genesis.py --output data/devnet/genesis.json --force
EOF
# Create systemd service for blockchain node
print_status "Creating systemd service for blockchain node..."
ssh ns3-root << 'EOF'
cat > /etc/systemd/system/blockchain-node.service << EOL
[Unit]
Description=AITBC Blockchain Node
After=network.target
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
cat > /etc/systemd/system/blockchain-rpc.service << EOL
[Unit]
Description=AITBC Blockchain RPC API
After=blockchain-node.service
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
systemctl daemon-reload
systemctl enable blockchain-node blockchain-rpc
EOF
# Start blockchain node
print_status "Starting blockchain node..."
ssh ns3-root "systemctl start blockchain-node blockchain-rpc"
# Wait for node to start
print_status "Waiting for blockchain node to start..."
sleep 5
# Check status
print_status "Checking blockchain node status..."
ssh ns3-root "systemctl status blockchain-node blockchain-rpc --no-pager | grep -E 'Active:|Main PID:'"
# Setup port forwarding
print_status "Setting up port forwarding..."
ssh ns3-root << 'EOF'
# Clear existing rules
iptables -t nat -F PREROUTING 2>/dev/null || true
iptables -t nat -F POSTROUTING 2>/dev/null || true
# Add port forwarding for blockchain RPC
iptables -t nat -A PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE
# Save rules
mkdir -p /etc/iptables
iptables-save > /etc/iptables/rules.v4
EOF
print_success "✅ Blockchain node deployed!"
echo ""
echo "Node RPC: http://192.168.100.10:8082"
echo "External RPC: http://aitbc.keisanki.net:8082"
echo ""
echo "Next: Deploying blockchain explorer..."

316
scripts/deploy/deploy-direct.sh Executable file
View File

@@ -0,0 +1,316 @@
#!/bin/bash
# Deploy blockchain node and explorer directly on ns3
set -e
echo "🚀 AITBC Direct Deployment on ns3"
echo "================================="
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Check if we're on ns3
if [ "$(hostname)" != "ns3" ] && [ "$(hostname)" != "aitbc" ]; then
print_warning "This script must be run on ns3 server"
echo "Run: ssh ns3-root"
echo "Then: cd /opt && ./deploy-direct.sh"
exit 1
fi
# Stop existing services
print_status "Stopping existing services..."
systemctl stop blockchain-node blockchain-rpc blockchain-explorer nginx 2>/dev/null || true
# Install dependencies
print_status "Installing dependencies..."
apt-get update
apt-get install -y python3 python3-venv python3-pip git curl nginx
# Deploy blockchain node
print_status "Deploying blockchain node..."
cd /opt
rm -rf blockchain-node
cp -r blockchain-node-src blockchain-node
cd blockchain-node
# Create configuration
print_status "Creating configuration..."
cat > .env << EOL
CHAIN_ID=ait-devnet
DB_PATH=./data/chain.db
RPC_BIND_HOST=0.0.0.0
RPC_BIND_PORT=8082
P2P_BIND_HOST=0.0.0.0
P2P_BIND_PORT=7070
PROPOSER_KEY=proposer_key_$(date +%s)
MINT_PER_UNIT=1000
COORDINATOR_RATIO=0.05
GOSSIP_BACKEND=memory
EOL
# Create fresh data directory
rm -rf data
mkdir -p data/devnet
# Setup Python environment
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .
# Generate genesis
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
python scripts/make_genesis.py --output data/devnet/genesis.json --force
# Create systemd services
print_status "Creating systemd services..."
cat > /etc/systemd/system/blockchain-node.service << EOL
[Unit]
Description=AITBC Blockchain Node
After=network.target
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
cat > /etc/systemd/system/blockchain-rpc.service << EOL
[Unit]
Description=AITBC Blockchain RPC API
After=blockchain-node.service
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
# Start blockchain services
print_status "Starting blockchain services..."
systemctl daemon-reload
systemctl enable blockchain-node blockchain-rpc
systemctl start blockchain-node blockchain-rpc
# Deploy explorer
print_status "Deploying blockchain explorer..."
cd /opt
rm -rf blockchain-explorer
mkdir -p blockchain-explorer
cd blockchain-explorer
# Create HTML explorer
cat > index.html << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AITBC Blockchain Explorer</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
</head>
<body class="bg-gray-50">
<header class="bg-blue-600 text-white shadow-lg">
<div class="container mx-auto px-4 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<i data-lucide="cube" class="w-8 h-8"></i>
<h1 class="text-2xl font-bold">AITBC Blockchain Explorer</h1>
</div>
<button onclick="refreshData()" class="bg-blue-500 hover:bg-blue-400 px-3 py-1 rounded flex items-center space-x-1">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
<span>Refresh</span>
</button>
</div>
</div>
</header>
<main class="container mx-auto px-4 py-8">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Current Height</p>
<p class="text-2xl font-bold" id="chain-height">-</p>
</div>
<i data-lucide="trending-up" class="w-10 h-10 text-green-500"></i>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Latest Block</p>
<p class="text-lg font-mono" id="latest-hash">-</p>
</div>
<i data-lucide="hash" class="w-10 h-10 text-blue-500"></i>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Node Status</p>
<p class="text-lg font-semibold" id="node-status">-</p>
</div>
<i data-lucide="activity" class="w-10 h-10 text-purple-500"></i>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b">
<h2 class="text-xl font-semibold flex items-center">
<i data-lucide="blocks" class="w-5 h-5 mr-2"></i>
Latest Blocks
</h2>
</div>
<div class="p-6">
<table class="w-full">
<thead>
<tr class="text-left text-gray-500 text-sm">
<th class="pb-3">Height</th>
<th class="pb-3">Hash</th>
<th class="pb-3">Timestamp</th>
<th class="pb-3">Transactions</th>
</tr>
</thead>
<tbody id="blocks-table">
<tr>
<td colspan="4" class="text-center py-8 text-gray-500">
Loading blocks...
</td>
</tr>
</tbody>
</table>
</div>
</div>
</main>
<script>
lucide.createIcons();
const RPC_URL = 'http://localhost:8082';
async function refreshData() {
try {
const response = await fetch(`${RPC_URL}/rpc/head`);
const head = await response.json();
document.getElementById('chain-height').textContent = head.height || '-';
document.getElementById('latest-hash').textContent = head.hash ? head.hash.substring(0, 16) + '...' : '-';
document.getElementById('node-status').innerHTML = '<span class="text-green-500">Online</span>';
// Load last 10 blocks
const tbody = document.getElementById('blocks-table');
tbody.innerHTML = '';
for (let i = 0; i < 10 && head.height - i >= 0; i++) {
const blockResponse = await fetch(`${RPC_URL}/rpc/blocks/${head.height - i}`);
const block = await blockResponse.json();
const row = tbody.insertRow();
row.innerHTML = `
<td class="py-3 font-mono">${block.height}</td>
<td class="py-3 font-mono text-sm">${block.hash ? block.hash.substring(0, 16) + '...' : '-'}</td>
<td class="py-3 text-sm">${new Date(block.timestamp * 1000).toLocaleString()}</td>
<td class="py-3">${block.transactions ? block.transactions.length : 0}</td>
`;
}
} catch (error) {
console.error('Error:', error);
document.getElementById('node-status').innerHTML = '<span class="text-red-500">Error</span>';
}
}
refreshData();
setInterval(refreshData, 30000);
</script>
</body>
</html>
EOF
# Configure nginx
print_status "Configuring nginx..."
cat > /etc/nginx/sites-available/blockchain-explorer << EOL
server {
listen 3000;
server_name _;
root /opt/blockchain-explorer;
index index.html;
location / {
try_files \$uri \$uri/ =404;
}
}
EOL
ln -sf /etc/nginx/sites-available/blockchain-explorer /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginx
# Setup port forwarding if in container
if [ "$(hostname)" = "aitbc" ]; then
print_status "Setting up port forwarding..."
iptables -t nat -F PREROUTING 2>/dev/null || true
iptables -t nat -F POSTROUTING 2>/dev/null || true
iptables -t nat -A PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE
iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE
iptables-save > /etc/iptables/rules.v4
fi
# Wait for services to start
print_status "Waiting for services to start..."
sleep 5
# Check services
print_status "Checking service status..."
systemctl status blockchain-node blockchain-rpc nginx --no-pager | grep -E 'Active:|Main PID:'
print_success "✅ Deployment complete!"
echo ""
echo "Services:"
if [ "$(hostname)" = "aitbc" ]; then
echo " - Blockchain Node RPC: http://192.168.100.10:8082"
echo " - Blockchain Explorer: http://192.168.100.10:3000"
echo ""
echo "External access:"
echo " - Blockchain Node RPC: http://aitbc.keisanki.net:8082"
echo " - Blockchain Explorer: http://aitbc.keisanki.net:3000"
else
echo " - Blockchain Node RPC: http://localhost:8082"
echo " - Blockchain Explorer: http://localhost:3000"
echo ""
echo "External access:"
echo " - Blockchain Node RPC: http://aitbc.keisanki.net:8082"
echo " - Blockchain Explorer: http://aitbc.keisanki.net:3000"
fi

88
scripts/deploy/deploy-domain.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/bash
# Deploy AITBC services to domain https://aitbc.bubuit.net
set -e
DOMAIN="aitbc.bubuit.net"
CONTAINER="aitbc"
echo "🚀 Deploying AITBC services to https://$DOMAIN"
echo ""
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Stop local services
print_status "Stopping local services..."
sudo fuser -k 8000/tcp 2>/dev/null || true
sudo fuser -k 9080/tcp 2>/dev/null || true
sudo fuser -k 3001/tcp 2>/dev/null || true
sudo fuser -k 3002/tcp 2>/dev/null || true
# Deploy to container
print_status "Deploying to container..."
python /home/oib/windsurf/aitbc/container-deploy.py
# Copy nginx config to container
print_status "Configuring nginx for domain..."
incus file push /home/oib/windsurf/aitbc/nginx-aitbc.conf $CONTAINER/etc/nginx/sites-available/aitbc
# Enable site
incus exec $CONTAINER -- ln -sf /etc/nginx/sites-available/aitbc /etc/nginx/sites-enabled/
incus exec $CONTAINER -- rm -f /etc/nginx/sites-enabled/default
# Test nginx config
incus exec $CONTAINER -- nginx -t
# Reload nginx
incus exec $CONTAINER -- systemctl reload nginx
# Install SSL certificate (Let's Encrypt)
print_warning "SSL Certificate Setup:"
echo "1. Ensure port 80/443 are forwarded to container IP (10.1.223.93)"
echo "2. Run certbot in container:"
echo " incus exec $CONTAINER -- certbot --nginx -d $DOMAIN"
echo ""
# Update UIs to use correct API endpoints
print_status "Updating API endpoints..."
# Update marketplace API base URL
incus exec $CONTAINER -- sed -i "s|http://127.0.0.1:8000|https://$DOMAIN/api|g" /home/oib/aitbc/apps/marketplace-ui/index.html
# Update exchange API endpoints
incus exec $CONTAINER -- sed -i "s|http://127.0.0.1:8000|https://$DOMAIN/api|g" /home/oib/aitbc/apps/trade-exchange/index.html
incus exec $CONTAINER -- sed -i "s|http://127.0.0.1:9080|https://$DOMAIN/rpc|g" /home/oib/aitbc/apps/trade-exchange/index.html
# Restart services to apply changes
print_status "Restarting services..."
incus exec $CONTAINER -- pkill -f "server.py"
sleep 2
incus exec $CONTAINER -- /home/oib/start_aitbc.sh
echo ""
print_status "✅ Deployment complete!"
echo ""
echo "📋 Service URLs:"
echo " 🌐 Domain: https://$DOMAIN"
echo " 📊 Marketplace: https://$DOMAIN/Marketplace"
echo " 💱 Trade Exchange: https://$DOMAIN/Exchange"
echo " 🔗 API: https://$DOMAIN/api"
echo " ⛓️ Blockchain RPC: https://$DOMAIN/rpc"
echo ""
echo "📝 Next Steps:"
echo "1. Forward ports 80/443 to container IP (10.1.223.93)"
echo "2. Install SSL certificate:"
echo " incus exec $CONTAINER -- certbot --nginx -d $DOMAIN"
echo "3. Test services at the URLs above"

View File

@@ -0,0 +1,74 @@
#!/bin/bash
# Deploy AITBC Trade Exchange to the server
set -e
SERVER="root@10.1.223.93"
EXCHANGE_DIR="/root/aitbc/apps/trade-exchange"
echo "🚀 Deploying AITBC Trade Exchange"
echo "=================================="
echo "Server: $SERVER"
echo ""
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Test SSH connection
print_status "Testing SSH connection..."
ssh $SERVER "hostname && ip a show eth0 | grep inet"
# Copy updated files
print_status "Copying updated Exchange files..."
scp /home/oib/windsurf/aitbc/apps/trade-exchange/index.html $SERVER:$EXCHANGE_DIR/
scp /home/oib/windsurf/aitbc/apps/trade-exchange/server.py $SERVER:$EXCHANGE_DIR/
# Ensure assets are available
print_status "Ensuring assets directory exists..."
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets"
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets/css"
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets/js"
# Copy assets if they don't exist
print_status "Copying assets if needed..."
if ! ssh $SERVER "test -f /var/www/aitbc.bubuit.net/assets/css/aitbc.css"; then
scp -r /home/oib/windsurf/aitbc/assets/* $SERVER:/var/www/aitbc.bubuit.net/assets/
fi
# Restart the exchange service
print_status "Restarting Trade Exchange service..."
ssh $SERVER "systemctl restart aitbc-exchange"
# Wait for service to start
print_status "Waiting for service to start..."
sleep 5
# Check service status
print_status "Checking service status..."
ssh $SERVER "systemctl status aitbc-exchange --no-pager -l | head -10"
# Test the endpoint
print_status "Testing Exchange endpoint..."
ssh $SERVER "curl -s http://127.0.0.1:3002/ | head -c 100"
echo ""
echo ""
print_status "✅ Exchange deployment complete!"
echo ""
echo "📋 URLs:"
echo " 🌐 IP: http://10.1.223.93/Exchange"
echo " 🔒 Domain: https://aitbc.bubuit.net/Exchange"
echo ""
echo "🔍 To check logs:"
echo " ssh $SERVER 'journalctl -u aitbc-exchange -f'"

View File

@@ -0,0 +1,396 @@
#!/bin/bash
# Deploy blockchain explorer directly on ns3 server
set -e
echo "🔍 Deploying Blockchain Explorer on ns3"
echo "======================================"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Check if we're on the right server
if [ "$(hostname)" != "ns3" ] && [ "$(hostname)" != "aitbc" ]; then
print_warning "This script should be run on ns3 server"
exit 1
fi
# Create directory
print_status "Creating blockchain explorer directory..."
mkdir -p /opt/blockchain-explorer
cd /opt/blockchain-explorer
# Create a simple HTML-based explorer (no build needed)
print_status "Creating web-based explorer..."
cat > index.html << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AITBC Blockchain Explorer</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<style>
.fade-in { animation: fadeIn 0.3s ease-in; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
</style>
</head>
<body class="bg-gray-50">
<header class="bg-blue-600 text-white shadow-lg">
<div class="container mx-auto px-4 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<i data-lucide="cube" class="w-8 h-8"></i>
<h1 class="text-2xl font-bold">AITBC Blockchain Explorer</h1>
</div>
<div class="flex items-center space-x-4">
<span class="text-sm">Network: <span class="font-mono bg-blue-700 px-2 py-1 rounded">ait-devnet</span></span>
<button onclick="refreshData()" class="bg-blue-500 hover:bg-blue-400 px-3 py-1 rounded flex items-center space-x-1">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
<span>Refresh</span>
</button>
</div>
</div>
</div>
</header>
<main class="container mx-auto px-4 py-8">
<!-- Chain Stats -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Current Height</p>
<p class="text-2xl font-bold" id="chain-height">-</p>
</div>
<i data-lucide="trending-up" class="w-10 h-10 text-green-500"></i>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Latest Block</p>
<p class="text-lg font-mono" id="latest-hash">-</p>
</div>
<i data-lucide="hash" class="w-10 h-10 text-blue-500"></i>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Node Status</p>
<p class="text-lg font-semibold" id="node-status">-</p>
</div>
<i data-lucide="activity" class="w-10 h-10 text-purple-500"></i>
</div>
</div>
</div>
<!-- Search -->
<div class="bg-white rounded-lg shadow p-6 mb-8">
<div class="flex space-x-4">
<input type="text" id="search-input" placeholder="Search by block height, hash, or transaction hash"
class="flex-1 px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<button onclick="search()" class="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700">
Search
</button>
</div>
</div>
<!-- Latest Blocks -->
<div class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b">
<h2 class="text-xl font-semibold flex items-center">
<i data-lucide="blocks" class="w-5 h-5 mr-2"></i>
Latest Blocks
</h2>
</div>
<div class="p-6">
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="text-left text-gray-500 text-sm">
<th class="pb-3">Height</th>
<th class="pb-3">Hash</th>
<th class="pb-3">Timestamp</th>
<th class="pb-3">Transactions</th>
<th class="pb-3">Actions</th>
</tr>
</thead>
<tbody id="blocks-table">
<tr>
<td colspan="5" class="text-center py-8 text-gray-500">
Loading blocks...
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Block Details Modal -->
<div id="block-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50">
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white rounded-lg max-w-4xl w-full max-h-[90vh] overflow-y-auto">
<div class="p-6 border-b">
<div class="flex justify-between items-center">
<h2 class="text-2xl font-bold">Block Details</h2>
<button onclick="closeModal()" class="text-gray-500 hover:text-gray-700">
<i data-lucide="x" class="w-6 h-6"></i>
</button>
</div>
</div>
<div class="p-6" id="block-details">
<!-- Block details will be loaded here -->
</div>
</div>
</div>
</div>
</main>
<footer class="bg-gray-800 text-white mt-12">
<div class="container mx-auto px-4 py-6 text-center">
<p class="text-sm">AITBC Blockchain Explorer - Connected to node at http://localhost:8082</p>
</div>
</footer>
<script>
// Initialize lucide icons
lucide.createIcons();
// RPC URL - change based on environment
const RPC_URL = window.location.hostname === 'localhost' ?
'http://localhost:8082' :
'http://95.216.198.140:8082';
// Global state
let currentData = {};
// Load initial data
document.addEventListener('DOMContentLoaded', () => {
refreshData();
});
// Refresh all data
async function refreshData() {
try {
await Promise.all([
loadChainStats(),
loadLatestBlocks()
]);
} catch (error) {
console.error('Error refreshing data:', error);
document.getElementById('node-status').innerHTML = '<span class="text-red-500">Error</span>';
}
}
// Load chain statistics
async function loadChainStats() {
const response = await fetch(`${RPC_URL}/rpc/head`);
const data = await response.json();
document.getElementById('chain-height').textContent = data.height || '-';
document.getElementById('latest-hash').textContent = data.hash ? data.hash.substring(0, 16) + '...' : '-';
document.getElementById('node-status').innerHTML = '<span class="text-green-500">Online</span>';
currentData.head = data;
}
// Load latest blocks
async function loadLatestBlocks() {
const tbody = document.getElementById('blocks-table');
tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-gray-500">Loading blocks...</td></tr>';
const head = await fetch(`${RPC_URL}/rpc/head`).then(r => r.json());
const blocks = [];
// Load last 10 blocks
for (let i = 0; i < 10 && head.height - i >= 0; i++) {
const block = await fetch(`${RPC_URL}/rpc/blocks/${head.height - i}`).then(r => r.json());
blocks.push(block);
}
tbody.innerHTML = blocks.map(block => `
<tr class="border-t hover:bg-gray-50">
<td class="py-3 font-mono">${block.height}</td>
<td class="py-3 font-mono text-sm">${block.hash ? block.hash.substring(0, 16) + '...' : '-'}</td>
<td class="py-3 text-sm">${formatTimestamp(block.timestamp)}</td>
<td class="py-3">${block.transactions ? block.transactions.length : 0}</td>
<td class="py-3">
<button onclick="showBlockDetails(${block.height})" class="text-blue-600 hover:text-blue-800">
View Details
</button>
</td>
</tr>
`).join('');
}
// Show block details
async function showBlockDetails(height) {
const block = await fetch(`${RPC_URL}/rpc/blocks/${height}`).then(r => r.json());
const modal = document.getElementById('block-modal');
const details = document.getElementById('block-details');
details.innerHTML = `
<div class="space-y-6">
<div>
<h3 class="text-lg font-semibold mb-2">Block Header</h3>
<div class="bg-gray-50 rounded p-4 space-y-2">
<div class="flex justify-between">
<span class="text-gray-600">Height:</span>
<span class="font-mono">${block.height}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Hash:</span>
<span class="font-mono text-sm">${block.hash || '-'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Parent Hash:</span>
<span class="font-mono text-sm">${block.parent_hash || '-'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Timestamp:</span>
<span>${formatTimestamp(block.timestamp)}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Proposer:</span>
<span class="font-mono text-sm">${block.proposer || '-'}</span>
</div>
</div>
</div>
${block.transactions && block.transactions.length > 0 ? `
<div>
<h3 class="text-lg font-semibold mb-2">Transactions (${block.transactions.length})</h3>
<div class="space-y-2">
${block.transactions.map(tx => `
<div class="bg-gray-50 rounded p-4">
<div class="flex justify-between mb-2">
<span class="text-gray-600">Hash:</span>
<span class="font-mono text-sm">${tx.hash || '-'}</span>
</div>
<div class="flex justify-between mb-2">
<span class="text-gray-600">Type:</span>
<span>${tx.type || '-'}</span>
</div>
<div class="flex justify-between mb-2">
<span class="text-gray-600">From:</span>
<span class="font-mono text-sm">${tx.sender || '-'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Fee:</span>
<span>${tx.fee || '0'}</span>
</div>
</div>
`).join('')}
</div>
</div>
` : '<p class="text-gray-500">No transactions in this block</p>'}
</div>
`;
modal.classList.remove('hidden');
}
// Close modal
function closeModal() {
document.getElementById('block-modal').classList.add('hidden');
}
// Search functionality
async function search() {
const query = document.getElementById('search-input').value.trim();
if (!query) return;
// Try block height first
if (/^\\d+$/.test(query)) {
showBlockDetails(parseInt(query));
return;
}
// TODO: Add transaction hash search
alert('Search by block height is currently supported');
}
// Format timestamp
function formatTimestamp(timestamp) {
if (!timestamp) return '-';
return new Date(timestamp * 1000).toLocaleString();
}
// Auto-refresh every 30 seconds
setInterval(refreshData, 30000);
</script>
</body>
</html>
EOF
# Install a simple web server
print_status "Installing web server..."
apt-get install -y nginx
# Configure nginx to serve the explorer
print_status "Configuring nginx..."
cat > /etc/nginx/sites-available/blockchain-explorer << EOL
server {
listen 3000;
server_name _;
root /opt/blockchain-explorer;
index index.html;
location / {
try_files \$uri \$uri/ =404;
}
# CORS headers for API access
location /rpc/ {
proxy_pass http://localhost:8082;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
}
}
EOL
# Enable the site
ln -sf /etc/nginx/sites-available/blockchain-explorer /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
# Test and reload nginx
nginx -t
systemctl reload nginx
# Setup port forwarding if in container
if [ "$(hostname)" = "aitbc" ]; then
print_status "Setting up port forwarding..."
iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE
iptables-save > /etc/iptables/rules.v4
fi
print_status "Checking nginx status..."
systemctl status nginx --no-pager | head -10
print_success "✅ Blockchain explorer deployed!"
echo ""
echo "Explorer URL: http://localhost:3000"
if [ "$(hostname)" = "aitbc" ]; then
echo "External URL: http://aitbc.keisanki.net:3000"
else
echo "External URL: http://aitbc.keisanki.net:3000"
fi
echo ""
echo "The explorer is a static HTML site served by nginx."

View File

@@ -0,0 +1,66 @@
#!/bin/bash
# Deploy AITBC Explorer to the server
set -e
SERVER="root@10.1.223.93"
EXPLORER_DIR="/root/aitbc/apps/explorer-web"
NGINX_CONFIG="/etc/nginx/sites-available/aitbc"
echo "🚀 Deploying AITBC Explorer to Server"
echo "====================================="
echo "Server: $SERVER"
echo ""
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Build the explorer locally first
print_status "Building explorer locally..."
cd /home/oib/windsurf/aitbc/apps/explorer-web
npm run build
# Copy built files to server
print_status "Copying explorer build to server..."
scp -r dist $SERVER:$EXPLORER_DIR/
# Update nginx config to include explorer
print_status "Updating nginx configuration..."
# Backup current config
ssh $SERVER "cp $NGINX_CONFIG ${NGINX_CONFIG}.backup"
# Add explorer location to nginx config
ssh $SERVER "sed -i '/# Health endpoint/i\\
# Explorer\\
location /explorer/ {\\
alias /root/aitbc/apps/explorer-web/dist/;\\
try_files \$uri \$uri/ /explorer/index.html;\\
}\\
\\
# Explorer mock data\\
location /explorer/mock/ {\\
alias /root/aitbc/apps/explorer-web/public/mock/;\\
}\\
' $NGINX_CONFIG"
# Test and reload nginx
print_status "Testing and reloading nginx..."
ssh $SERVER "nginx -t && systemctl reload nginx"
print_status "✅ Explorer deployment complete!"
echo ""
echo "📋 Explorer URL:"
echo " 🌐 Explorer: https://aitbc.bubuit.net/explorer/"
echo ""

View File

@@ -0,0 +1,121 @@
#!/bin/bash
# Deploy the first blockchain node
set -e
echo "🚀 Deploying First Blockchain Node"
echo "================================="
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
NODE1_DIR="/opt/blockchain-node"
# Create configuration for first node
print_status "Creating configuration for first node..."
cat > $NODE1_DIR/.env << EOF
CHAIN_ID=ait-devnet
DB_PATH=./data/chain.db
RPC_BIND_HOST=127.0.0.1
RPC_BIND_PORT=8080
P2P_BIND_HOST=0.0.0.0
P2P_BIND_PORT=7070
PROPOSER_KEY=node1_proposer_key_$(date +%s)
MINT_PER_UNIT=1000
COORDINATOR_RATIO=0.05
GOSSIP_BACKEND=http
GOSSIP_BROADCAST_URL=http://127.0.0.1:7071/gossip
EOF
# Create data directory
mkdir -p $NODE1_DIR/data/devnet
# Generate genesis file
print_status "Generating genesis file..."
cd $NODE1_DIR
export PYTHONPATH="${NODE1_DIR}/src:${NODE1_DIR}/scripts:${PYTHONPATH:-}"
python3 scripts/make_genesis.py --output data/devnet/genesis.json --force
# Create systemd service
print_status "Creating systemd service..."
sudo cat > /etc/systemd/system/blockchain-node.service << EOF
[Unit]
Description=AITBC Blockchain Node 1
After=network.target
[Service]
Type=exec
User=root
WorkingDirectory=$NODE1_DIR
Environment=PATH=$NODE1_DIR/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=$NODE1_DIR/src:$NODE1_DIR/scripts
ExecStart=$NODE1_DIR/.venv/bin/python3 -m aitbc_chain.main
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# Create RPC API service
print_status "Creating RPC API service..."
sudo cat > /etc/systemd/system/blockchain-rpc.service << EOF
[Unit]
Description=AITBC Blockchain RPC API 1
After=blockchain-node.service
[Service]
Type=exec
User=root
WorkingDirectory=$NODE1_DIR
Environment=PATH=$NODE1_DIR/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=$NODE1_DIR/src:$NODE1_DIR/scripts
ExecStart=$NODE1_DIR/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8080
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# Setup Python environment if not exists
if [ ! -d "$NODE1_DIR/.venv" ]; then
print_status "Setting up Python environment..."
cd $NODE1_DIR
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .
fi
# Enable and start services
print_status "Enabling and starting services..."
sudo systemctl daemon-reload
sudo systemctl enable blockchain-node blockchain-rpc
sudo systemctl start blockchain-node blockchain-rpc
# Check status
print_status "Checking service status..."
sudo systemctl status blockchain-node --no-pager -l
sudo systemctl status blockchain-rpc --no-pager -l
echo ""
print_status "✅ First blockchain node deployed!"
echo ""
echo "Node 1 RPC: http://127.0.0.1:8080"
echo "Node 2 RPC: http://127.0.0.1:8081"
echo ""
echo "To check logs:"
echo " Node 1: sudo journalctl -u blockchain-node -f"
echo " Node 2: sudo journalctl -u blockchain-node-2 -f"

View File

@@ -0,0 +1,306 @@
#!/bin/bash
# Deploy blockchain node and explorer inside the container
set -e
echo "🚀 Deploying Inside Container"
echo "============================"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Check if we're in the container
if [ ! -f /proc/1/environ ] || ! grep -q container=lxc /proc/1/environ 2>/dev/null; then
if [ "$(hostname)" != "aitbc" ]; then
print_warning "This script must be run inside the aitbc container"
exit 1
fi
fi
# Stop existing services
print_status "Stopping existing services..."
systemctl stop blockchain-node blockchain-rpc nginx 2>/dev/null || true
# Install dependencies
print_status "Installing dependencies..."
apt-get update
apt-get install -y python3 python3-venv python3-pip git curl nginx
# Deploy blockchain node
print_status "Deploying blockchain node..."
cd /opt
rm -rf blockchain-node
# The source is already in blockchain-node-src, copy it properly
cp -r blockchain-node-src blockchain-node
cd blockchain-node
# Check if pyproject.toml exists
if [ ! -f pyproject.toml ]; then
print_warning "pyproject.toml not found, looking for it..."
find . -name "pyproject.toml" -type f
# If it's in a subdirectory, move everything up
if [ -f blockchain-node-src/pyproject.toml ]; then
print_status "Moving files from nested directory..."
mv blockchain-node-src/* .
rmdir blockchain-node-src
fi
fi
# Create configuration
print_status "Creating configuration..."
cat > .env << EOL
CHAIN_ID=ait-devnet
DB_PATH=./data/chain.db
RPC_BIND_HOST=0.0.0.0
RPC_BIND_PORT=8082
P2P_BIND_HOST=0.0.0.0
P2P_BIND_PORT=7070
PROPOSER_KEY=proposer_key_$(date +%s)
MINT_PER_UNIT=1000
COORDINATOR_RATIO=0.05
GOSSIP_BACKEND=memory
EOL
# Create fresh data directory
rm -rf data
mkdir -p data/devnet
# Setup Python environment
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .
# Generate genesis
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
python scripts/make_genesis.py --output data/devnet/genesis.json --force
# Create systemd services
print_status "Creating systemd services..."
cat > /etc/systemd/system/blockchain-node.service << EOL
[Unit]
Description=AITBC Blockchain Node
After=network.target
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
cat > /etc/systemd/system/blockchain-rpc.service << EOL
[Unit]
Description=AITBC Blockchain RPC API
After=blockchain-node.service
[Service]
Type=exec
User=root
WorkingDirectory=/opt/blockchain-node
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOL
# Start blockchain services
print_status "Starting blockchain services..."
systemctl daemon-reload
systemctl enable blockchain-node blockchain-rpc
systemctl start blockchain-node blockchain-rpc
# Deploy explorer
print_status "Deploying blockchain explorer..."
cd /opt
rm -rf blockchain-explorer
mkdir -p blockchain-explorer
cd blockchain-explorer
# Create HTML explorer
cat > index.html << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AITBC Blockchain Explorer</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
</head>
<body class="bg-gray-50">
<header class="bg-blue-600 text-white shadow-lg">
<div class="container mx-auto px-4 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<i data-lucide="cube" class="w-8 h-8"></i>
<h1 class="text-2xl font-bold">AITBC Blockchain Explorer</h1>
</div>
<button onclick="refreshData()" class="bg-blue-500 hover:bg-blue-400 px-3 py-1 rounded flex items-center space-x-1">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
<span>Refresh</span>
</button>
</div>
</div>
</header>
<main class="container mx-auto px-4 py-8">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Current Height</p>
<p class="text-2xl font-bold" id="chain-height">-</p>
</div>
<i data-lucide="trending-up" class="w-10 h-10 text-green-500"></i>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Latest Block</p>
<p class="text-lg font-mono" id="latest-hash">-</p>
</div>
<i data-lucide="hash" class="w-10 h-10 text-blue-500"></i>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Node Status</p>
<p class="text-lg font-semibold" id="node-status">-</p>
</div>
<i data-lucide="activity" class="w-10 h-10 text-purple-500"></i>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b">
<h2 class="text-xl font-semibold flex items-center">
<i data-lucide="blocks" class="w-5 h-5 mr-2"></i>
Latest Blocks
</h2>
</div>
<div class="p-6">
<table class="w-full">
<thead>
<tr class="text-left text-gray-500 text-sm">
<th class="pb-3">Height</th>
<th class="pb-3">Hash</th>
<th class="pb-3">Timestamp</th>
<th class="pb-3">Transactions</th>
</tr>
</thead>
<tbody id="blocks-table">
<tr>
<td colspan="4" class="text-center py-8 text-gray-500">
Loading blocks...
</td>
</tr>
</tbody>
</table>
</div>
</div>
</main>
<script>
lucide.createIcons();
const RPC_URL = 'http://localhost:8082';
async function refreshData() {
try {
const response = await fetch(`${RPC_URL}/rpc/head`);
const head = await response.json();
document.getElementById('chain-height').textContent = head.height || '-';
document.getElementById('latest-hash').textContent = head.hash ? head.hash.substring(0, 16) + '...' : '-';
document.getElementById('node-status').innerHTML = '<span class="text-green-500">Online</span>';
// Load last 10 blocks
const tbody = document.getElementById('blocks-table');
tbody.innerHTML = '';
for (let i = 0; i < 10 && head.height - i >= 0; i++) {
const blockResponse = await fetch(`${RPC_URL}/rpc/blocks/${head.height - i}`);
const block = await blockResponse.json();
const row = tbody.insertRow();
row.innerHTML = `
<td class="py-3 font-mono">${block.height}</td>
<td class="py-3 font-mono text-sm">${block.hash ? block.hash.substring(0, 16) + '...' : '-'}</td>
<td class="py-3 text-sm">${new Date(block.timestamp * 1000).toLocaleString()}</td>
<td class="py-3">${block.transactions ? block.transactions.length : 0}</td>
`;
}
} catch (error) {
console.error('Error:', error);
document.getElementById('node-status').innerHTML = '<span class="text-red-500">Error</span>';
}
}
refreshData();
setInterval(refreshData, 30000);
</script>
</body>
</html>
EOF
# Configure nginx
print_status "Configuring nginx..."
cat > /etc/nginx/sites-available/blockchain-explorer << EOL
server {
listen 3000;
server_name _;
root /opt/blockchain-explorer;
index index.html;
location / {
try_files \$uri \$uri/ =404;
}
}
EOL
ln -sf /etc/nginx/sites-available/blockchain-explorer /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginx
# Wait for services to start
print_status "Waiting for services to start..."
sleep 5
# Check services
print_status "Checking service status..."
systemctl status blockchain-node blockchain-rpc nginx --no-pager | grep -E 'Active:|Main PID:'
print_success "✅ Deployment complete in container!"
echo ""
echo "Services:"
echo " - Blockchain Node RPC: http://localhost:8082"
echo " - Blockchain Explorer: http://localhost:3000"
echo ""
echo "These are accessible from the host via port forwarding."

View File

@@ -0,0 +1,56 @@
#!/bin/bash
# Deploy Modern Blockchain Explorer
set -e
echo "🚀 Deploying Modern Blockchain Explorer"
echo "======================================"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Stop existing services
print_status "Stopping existing services..."
systemctl stop nginx 2>/dev/null || true
# Create directory
print_status "Creating explorer directory..."
rm -rf /opt/blockchain-explorer
mkdir -p /opt/blockchain-explorer/assets
# Copy files
print_status "Copying explorer files..."
cp -r /opt/blockchain-node-src/apps/blockchain-explorer/* /opt/blockchain-explorer/
# Update nginx configuration
print_status "Updating nginx configuration..."
cp /opt/blockchain-explorer/nginx.conf /etc/nginx/sites-available/blockchain-explorer
ln -sf /etc/nginx/sites-available/blockchain-explorer /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
# Test and start nginx
print_status "Starting nginx..."
nginx -t
systemctl start nginx
print_success "✅ Modern explorer deployed!"
echo ""
echo "Access URLs:"
echo " - Explorer: http://localhost:3000/"
echo " - API: http://localhost:3000/api/v1/"
echo ""
echo "Standardized API Endpoints:"
echo " - GET /api/v1/chain/head"
echo " - GET /api/v1/chain/blocks?limit=N"
echo " - GET /api/v1/chain/blocks/{height}"

View File

@@ -0,0 +1,160 @@
#!/bin/bash
# Deploy nginx reverse proxy for AITBC services
# This replaces firehol/iptables port forwarding with nginx reverse proxy
set -e
echo "🚀 Deploying Nginx Reverse Proxy for AITBC"
echo "=========================================="
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if we're on the host server
if ! grep -q "ns3-root" ~/.ssh/config 2>/dev/null; then
print_error "ns3-root SSH configuration not found. Please add it to ~/.ssh/config"
exit 1
fi
# Install nginx on host if not already installed
print_status "Checking nginx installation on host..."
ssh ns3-root "which nginx > /dev/null || (apt-get update && apt-get install -y nginx)"
# Install certbot for SSL certificates
print_status "Checking certbot installation..."
ssh ns3-root "which certbot > /dev/null || (apt-get update && apt-get install -y certbot python3-certbot-nginx)"
# Copy nginx configuration
print_status "Copying nginx configuration..."
scp infra/nginx/nginx-aitbc-reverse-proxy.conf ns3-root:/tmp/aitbc-reverse-proxy.conf
# Backup existing nginx configuration
print_status "Backing up existing nginx configuration..."
ssh ns3-root "mkdir -p /etc/nginx/backup && cp -r /etc/nginx/sites-available/* /etc/nginx/backup/ 2>/dev/null || true"
# Install the new configuration
print_status "Installing nginx reverse proxy configuration..."
ssh ns3-root << 'EOF'
# Remove existing configurations
rm -f /etc/nginx/sites-enabled/default
rm -f /etc/nginx/sites-available/aitbc*
# Copy new configuration
cp /tmp/aitbc-reverse-proxy.conf /etc/nginx/sites-available/aitbc-reverse-proxy.conf
# Create symbolic link
ln -sf /etc/nginx/sites-available/aitbc-reverse-proxy.conf /etc/nginx/sites-enabled/
# Test nginx configuration
nginx -t
EOF
# Check if SSL certificate exists
print_status "Checking SSL certificate..."
if ! ssh ns3-root "test -f /etc/letsencrypt/live/aitbc.keisanki.net/fullchain.pem"; then
print_warning "SSL certificate not found. Obtaining Let's Encrypt certificate..."
# Obtain SSL certificate
ssh ns3-root << 'EOF'
# Stop nginx temporarily
systemctl stop nginx 2>/dev/null || true
# Obtain certificate
certbot certonly --standalone -d aitbc.keisanki.net -d api.aitbc.keisanki.net -d rpc.aitbc.keisanki.net --email admin@keisanki.net --agree-tos --non-interactive
# Start nginx
systemctl start nginx
EOF
if [ $? -ne 0 ]; then
print_error "Failed to obtain SSL certificate. Please run certbot manually:"
echo "certbot certonly --standalone -d aitbc.keisanki.net -d api.aitbc.keisanki.net -d rpc.aitbc.keisanki.net"
exit 1
fi
fi
# Restart nginx
print_status "Restarting nginx..."
ssh ns3-root "systemctl restart nginx && systemctl enable nginx"
# Remove old iptables rules (optional)
print_warning "Removing old iptables port forwarding rules (if they exist)..."
ssh ns3-root << 'EOF'
# Flush existing NAT rules for AITBC ports
iptables -t nat -D PREROUTING -p tcp --dport 8000 -j DNAT --to-destination 192.168.100.10:8000 2>/dev/null || true
iptables -t nat -D POSTROUTING -p tcp -d 192.168.100.10 --dport 8000 -j MASQUERADE 2>/dev/null || true
iptables -t nat -D PREROUTING -p tcp --dport 8081 -j DNAT --to-destination 192.168.100.10:8081 2>/dev/null || true
iptables -t nat -D POSTROUTING -p tcp -d 192.168.100.10 --dport 8081 -j MASQUERADE 2>/dev/null || true
iptables -t nat -D PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082 2>/dev/null || true
iptables -t nat -D POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE 2>/dev/null || true
iptables -t nat -D PREROUTING -p tcp --dport 9080 -j DNAT --to-destination 192.168.100.10:9080 2>/dev/null || true
iptables -t nat -D POSTROUTING -p tcp -d 192.168.100.10 --dport 9080 -j MASQUERADE 2>/dev/null || true
iptables -t nat -D PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000 2>/dev/null || true
iptables -t nat -D POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE 2>/dev/null || true
# Save iptables rules
iptables-save > /etc/iptables/rules.v4 2>/dev/null || true
EOF
# Wait for nginx to start
sleep 2
# Test the configuration
print_status "Testing reverse proxy configuration..."
echo ""
# Test main domain
if curl -s -o /dev/null -w "%{http_code}" https://aitbc.keisanki.net/health | grep -q "200"; then
print_status "✅ Main domain (aitbc.keisanki.net) - OK"
else
print_error "❌ Main domain (aitbc.keisanki.net) - FAILED"
fi
# Test API endpoint
if curl -s -o /dev/null -w "%{http_code}" https://aitbc.keisanki.net/api/health | grep -q "200"; then
print_status "✅ API endpoint - OK"
else
print_warning "⚠️ API endpoint - Not responding (service may not be running)"
fi
# Test RPC endpoint
if curl -s -o /dev/null -w "%{http_code}" https://aitbc.keisanki.net/rpc/head | grep -q "200"; then
print_status "✅ RPC endpoint - OK"
else
print_warning "⚠️ RPC endpoint - Not responding (blockchain node may not be running)"
fi
echo ""
print_status "🎉 Nginx reverse proxy deployment complete!"
echo ""
echo "Service URLs:"
echo " • Blockchain Explorer: https://aitbc.keisanki.net"
echo " • API: https://aitbc.keisanki.net/api/"
echo " • RPC: https://aitbc.keisanki.net/rpc/"
echo " • Exchange: https://aitbc.keisanki.net/exchange/"
echo ""
echo "Alternative URLs:"
echo " • API-only: https://api.aitbc.keisanki.net"
echo " • RPC-only: https://rpc.aitbc.keisanki.net"
echo ""
echo "Note: Make sure all services are running in the container:"
echo " • blockchain-explorer.service (port 3000)"
echo " • coordinator-api.service (port 8000)"
echo " • blockchain-rpc.service (port 8082)"
echo " • aitbc-exchange.service (port 9080)"

View File

@@ -0,0 +1,55 @@
#!/bin/bash
echo "🚀 Deploying AITBC for Production..."
# 1. Setup production assets
echo "📦 Setting up production assets..."
bash setup-production-assets.sh
# 2. Copy assets to server
echo "📋 Copying assets to server..."
scp -r assets/ aitbc:/var/www/html/
# 3. Update Nginx configuration
echo "⚙️ Updating Nginx configuration..."
ssh aitbc "cat >> /etc/nginx/sites-available/aitbc.conf << 'EOF'
# Serve production assets
location /assets/ {
alias /var/www/html/assets/;
expires 1y;
add_header Cache-Control \"public, immutable\";
add_header X-Content-Type-Options nosniff;
# Gzip compression
gzip on;
gzip_types text/css application/javascript image/svg+xml;
}
# Security headers
add_header Referrer-Policy \"strict-origin-when-cross-origin\" always;
add_header X-Frame-Options \"SAMEORIGIN\" always;
add_header X-Content-Type-Options \"nosniff\" always;
EOF"
# 4. Reload Nginx
echo "🔄 Reloading Nginx..."
ssh aitbc "nginx -t && systemctl reload nginx"
# 5. Update Exchange page to use production assets
echo "🔄 Updating Exchange page..."
scp apps/trade-exchange/index.prod.html aitbc:/root/aitbc/apps/trade-exchange/index.html
# 6. Update Marketplace page
echo "🔄 Updating Marketplace page..."
sed -i 's|https://cdn.tailwindcss.com|/assets/js/tailwind.js|g' apps/marketplace-ui/index.html
sed -i 's|https://unpkg.com/axios/dist/axios.min.js|/assets/js/axios.min.js|g' apps/marketplace-ui/index.html
sed -i 's|https://unpkg.com/lucide@latest|/assets/js/lucide.js|g' apps/marketplace-ui/index.html
scp apps/marketplace-ui/index.html aitbc:/root/aitbc/apps/marketplace-ui/
echo "✅ Production deployment complete!"
echo ""
echo "📝 Next steps:"
echo "1. Restart services: ssh aitbc 'systemctl restart aitbc-exchange aitbc-marketplace-ui'"
echo "2. Clear browser cache"
echo "3. Test all pages"

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