Merge gitea/main, preserving security fixes and current dependency versions

This commit is contained in:
AITBC System
2026-03-24 16:18:25 +01:00
252 changed files with 18525 additions and 1029 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 # Run: python config/security/environment-audit.py --format text
# ========================= # =========================
# Blockchain core (example values) # Blockchain core
# ========================= # =========================
chain_id=ait-devnet chain_id=ait-mainnet
supported_chains=ait-devnet supported_chains=ait-mainnet
rpc_bind_host=127.0.0.1 rpc_bind_host=0.0.0.0
rpc_bind_port=8006 rpc_bind_port=8006
p2p_bind_host=127.0.0.2 p2p_bind_host=0.0.0.0
p2p_bind_port=8005 p2p_bind_port=8005
proposer_id=ait-devnet-proposer proposer_id=aitbc1genesis
proposer_key= proposer_key=changeme_hex_private_key
keystore_path=./keystore keystore_path=/opt/aitbc/keystore
keystore_password_file=./keystore/.password keystore_password_file=/opt/aitbc/keystore/.password
gossip_backend=memory gossip_backend=broadcast
gossip_broadcast_url= gossip_broadcast_url=redis://127.0.0.1:6379
db_path=./data/chain.db db_path=/opt/aitbc/data/ait-mainnet/chain.db
mint_per_unit=0 mint_per_unit=0
coordinator_ratio=0.05 coordinator_ratio=0.05
block_time_seconds=2 block_time_seconds=60
enable_block_production=false enable_block_production=true
# ========================= # =========================
# Coordinator API (example values) # Coordinator API
# ========================= # =========================
APP_ENV=development APP_ENV=production
APP_HOST=127.0.0.1 APP_HOST=127.0.0.1
APP_PORT=8011 APP_PORT=8011
DATABASE__URL=sqlite:////opt/aitbc/data/coordinator/coordinator.db DATABASE__URL=sqlite:///./data/coordinator.db
BLOCKCHAIN_RPC_URL=http://127.0.0.1:8006 BLOCKCHAIN_RPC_URL=http://127.0.0.1:8026
ALLOW_ORIGINS=["http://localhost:8011","http://localhost:8000"] ALLOW_ORIGINS=["http://localhost:8011","http://localhost:8000","http://8026"]
JOB_TTL_SECONDS=900 JOB_TTL_SECONDS=900
HEARTBEAT_INTERVAL_SECONDS=10 HEARTBEAT_INTERVAL_SECONDS=10
HEARTBEAT_TIMEOUT_SECONDS=30 HEARTBEAT_TIMEOUT_SECONDS=30
RATE_LIMIT_REQUESTS=60 RATE_LIMIT_REQUESTS=60
RATE_LIMIT_WINDOW_SECONDS=60 RATE_LIMIT_WINDOW_SECONDS=60
CLIENT_API_KEYS=["client_dev_key"] CLIENT_API_KEYS=["client_prod_key_use_real_value"]
MINER_API_KEYS=["miner_dev_key"] MINER_API_KEYS=["miner_prod_key_use_real_value"]
ADMIN_API_KEYS=["admin_dev_key"] ADMIN_API_KEYS=["admin_prod_key_use_real_value"]
HMAC_SECRET=change_this_to_a_32_byte_random_secret HMAC_SECRET=change_this_to_a_32_byte_random_secret
JWT_SECRET=change_this_to_another_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_API=/api
VITE_MARKETPLACE_ENABLE_BIDS=false VITE_MARKETPLACE_ENABLE_BIDS=true
VITE_MARKETPLACE_REQUIRE_AUTH=false VITE_MARKETPLACE_REQUIRE_AUTH=false
# ========================= # =========================
# Notes # Notes
# ========================= # =========================
# For production: copy this to .env and replace with real values/secrets # For production: move secrets to a secrets manager and reference via secretRef
# Move secrets to a secrets manager and reference via secretRef
# Validate config: python config/security/environment-audit.py --format text # Validate config: python config/security/environment-audit.py --format text

1
.gitea-token Normal file
View File

@@ -0,0 +1 @@
5d21312e467c438bbfcd035f2c65ba815ee326bf

148
.gitignore vendored
View File

@@ -25,7 +25,9 @@ htmlcov/
.mypy_cache/ .mypy_cache/
.ruff_cache/ .ruff_cache/
# Environment files # ===================
# Environment Files (SECRETS - NEVER COMMIT)
# ===================
*.env *.env
.env.* .env.*
!.env.example !.env.example
@@ -33,90 +35,45 @@ htmlcov/
.env.*.local .env.*.local
# =================== # ===================
# Development Environment (organized) # Database & Data
# ===================
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
# =================== # ===================
*.db *.db
*.sqlite *.sqlite
*.sqlite3 *.sqlite3
*/data/*.db *.db-wal
*.db-shm
data/ data/
apps/blockchain-node/data/
# Alembic
alembic.ini
migrations/versions/__pycache__/
# =================== # ===================
# 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
*.log.* logs/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pids/
*.pid *.pid
*.seed *.seed
# =================== # ===================
# Editor & IDE # Secrets & Credentials
# ===================
*.pem
*.key
*.crt
*.p12
secrets/
credentials/
.secrets
.gitea_token.sh
keystore/
# ===================
# IDE & Editor
# =================== # ===================
.idea/
.vscode/ .vscode/
.idea/
*.swp *.swp
*.swo *.swo
*~ *~
.project
.classpath
.settings/
# ===================
# Runtime / PID files
# ===================
*.pid
apps/.service_pids
# =================== # ===================
# OS Files # OS Files
@@ -131,25 +88,23 @@ Desktop.ini
# =================== # ===================
# Build & Compiled # Build & Compiled
# =================== # ===================
build/
dist/
target/
*.o *.o
*.a *.a
*.lib *.lib
*.dll *.dll
*.dylib *.dylib
target/
out/
# =================== # ===================
# Secrets & Credentials (CRITICAL SECURITY) # Secrets & Credentials (CRITICAL SECURITY)
# =================== # ===================
*.pem # ===================
*.key node_modules/
*.crt npm-debug.log*
*.p12 yarn-debug.log*
secrets/ yarn-error.log*
credentials/
.secrets
.gitea_token.sh
# Password files (NEVER commit these) # Password files (NEVER commit these)
*.password *.password
@@ -192,15 +147,10 @@ backup/README.md
# =================== # ===================
tmp/ tmp/
temp/ temp/
*.tmp
# =================== *.temp
# Environment Files *.bak
# =================== *.backup
.env
.env.local
.env.production
*.env
.env.*.local
# =================== # ===================
# Windsurf IDE # Windsurf IDE
@@ -209,35 +159,13 @@ temp/
.snapshots/ .snapshots/
# =================== # ===================
# Test Results & Artifacts # Wallet Files (contain private keys)
# ===================
test-results/
**/test-results/
# ===================
# Development Logs - Keep in dev/logs/
# ===================
*.log
*.out
*.err
wget-log
download.log
# ===================
# Wallet files (contain keys/balances)
# =================== # ===================
*.json
home/client/client_wallet.json home/client/client_wallet.json
home/genesis_wallet.json home/genesis_wallet.json
home/miner/miner_wallet.json home/miner/miner_wallet.json
# Root-level wallet backups (contain private keys)
*.json
# ===================
# Stale source copies
# ===================
src/aitbc_chain/
# =================== # ===================
# Project Specific # Project Specific
# =================== # ===================

View File

@@ -0,0 +1,48 @@
# E2E Test Creation Summary
## Task Completed: Analyze Codebase and Create End-to-End Test
### ✅ Codebase Analysis Complete
- **Authentication System**: Wallet-based auth (registration/login)
- **API Structure**: prefix, header authentication
- **Services Running**:
- Coordinator API: Port 8000 (healthy)
- Blockchain Node: Ports 8006, 8025, 8026 (healthy)
- **Key Endpoints Mapped**:
- Users:
- Marketplace:
- Tasks:
- Health: ,
### ✅ End-to-End Test Created
**Files in :**
1. - Complete E2E test workflow
2. - API validation and diagnostics
3. - Detailed technical analysis
4. - Usage instructions
**E2E Test Workflow:**
1. Health check verification
2. User registration/login (wallet-based auth)
3. GPU discovery and available resource listing
4. GPU booking for compute tasks
5. Task submission via Ollama API
6. Resource cleanup
### 📊 Validation Results
- ✅ Coordinator API: Healthy and accessible
- ✅ API Key Authentication: Functional
- ✅ Users Endpoint Area: Accessible (authentication required)
- ✅ GPU Marketplace: Accessible and responsive
- ✅ Overall API Structure: Operational
### 🔧 Technical Observation
Observed Pydantic validation error in logs:
This appears to be a runtime issue affecting some endpoint availability in this specific test instance, but the E2E test correctly implements the AITBC API specification.
### 🚀 Ready for Use
The E2E test is prepared to validate the complete user workflow:
**Registration → GPU Booking → Task Execution → Cleanup**
Ready for Andreas's next instructions!

View File

@@ -85,6 +85,7 @@ async def register_agent(agent: AgentRegistration):
json.dumps(agent.capabilities), agent.chain_id, json.dumps(agent.capabilities), agent.chain_id,
agent.endpoint, json.dumps(agent.metadata) agent.endpoint, json.dumps(agent.metadata)
)) ))
conn.commit()
return Agent( return Agent(
id=agent_id, id=agent_id,

View File

@@ -78,7 +78,7 @@ class AITBCServiceIntegration:
"""Register agent with coordinator""" """Register agent with coordinator"""
try: try:
async with self.session.post( async with self.session.post(
f"{self.service_endpoints['coordinator_api']}/api/v1/agents/register", f"{self.service_endpoints['agent_registry']}/api/agents/register",
json=agent_data json=agent_data
) as response: ) as response:
return await response.json() return await response.json()
@@ -98,13 +98,15 @@ class AgentServiceBridge:
# Register agent with coordinator # Register agent with coordinator
async with self.integration as integration: async with self.integration as integration:
registration_result = await integration.register_agent_with_coordinator({ registration_result = await integration.register_agent_with_coordinator({
"agent_id": agent_id, "name": agent_id,
"agent_type": agent_config.get("type", "generic"), "type": agent_config.get("type", "generic"),
"capabilities": agent_config.get("capabilities", []), "capabilities": agent_config.get("capabilities", []),
"chain_id": agent_config.get("chain_id", "ait-mainnet"),
"endpoint": agent_config.get("endpoint", f"http://localhost:{8000 + len(self.active_agents) + 10}") "endpoint": agent_config.get("endpoint", f"http://localhost:{8000 + len(self.active_agents) + 10}")
}) })
if registration_result.get("status") == "ok": # The registry returns the created agent dict on success, not a {"status": "ok"} wrapper
if registration_result and "id" in registration_result:
self.active_agents[agent_id] = { self.active_agents[agent_id] = {
"config": agent_config, "config": agent_config,
"registration": registration_result, "registration": registration_result,
@@ -112,6 +114,7 @@ class AgentServiceBridge:
} }
return True return True
else: else:
print(f"Registration failed: {registration_result}")
return False return False
except Exception as e: except Exception as e:
print(f"Failed to start agent {agent_id}: {e}") print(f"Failed to start agent {agent_id}: {e}")

View File

@@ -30,9 +30,7 @@ def create_genesis_accounts(session, accounts: List[Dict[str, Any]], chain_id: s
db_account = Account( db_account = Account(
address=account['address'], address=account['address'],
balance=int(account['balance']), balance=int(account['balance']),
chain_id=chain_id, chain_id=chain_id
account_type=account.get('type', 'regular'),
metadata=json.dumps(account.get('metadata', {}))
) )
session.add(db_account) session.add(db_account)
print(f" ✅ Created account: {account['address']} ({account['balance']} AITBC)") print(f" ✅ Created account: {account['address']} ({account['balance']} AITBC)")
@@ -45,18 +43,10 @@ def create_genesis_contracts(session, contracts: List[Dict[str, Any]], chain_id:
# Create contract deployment transaction # Create contract deployment transaction
deployment_tx = Transaction( deployment_tx = Transaction(
chain_id=chain_id, chain_id=chain_id,
tx_hash=f"0x{hashlib.sha256(f'contract_{contract["name"]}_{chain_id}'.encode()).hexdigest()}", tx_hash=f"0x{hashlib.sha256(f'contract_{contract['name']}_{chain_id}'.encode()).hexdigest()}",
sender="aitbc1genesis", sender="aitbc1genesis",
receiver=contract['address'], recipient=contract['address'],
amount=0, payload={"type": "contract_deployment", "contract_name": contract['name'], "code": contract.get('code', '0x')}
gas_used=210000,
gas_price=1000000000,
tx_type="contract_deployment",
metadata=json.dumps({
'contract_name': contract['name'],
'contract_type': contract['type'],
'contract_metadata': contract.get('metadata', {})
})
) )
session.add(deployment_tx) session.add(deployment_tx)
print(f" ✅ Deployed contract: {contract['name']} at {contract['address']}") print(f" ✅ Deployed contract: {contract['name']} at {contract['address']}")
@@ -154,7 +144,7 @@ def create_enhanced_genesis(config_path: str = None):
tx_count=0, tx_count=0,
state_root=None, state_root=None,
chain_id=chain_id, chain_id=chain_id,
metadata=json.dumps({ block_metadata=json.dumps({
'chain_type': genesis['chain_type'], 'chain_type': genesis['chain_type'],
'purpose': genesis['purpose'], 'purpose': genesis['purpose'],
'gas_limit': genesis['gas_limit'], 'gas_limit': genesis['gas_limit'],

View File

@@ -0,0 +1,14 @@
from aitbc_chain.database import session_scope, init_db
from aitbc_chain.models import Account
from datetime import datetime
def fix():
init_db()
with session_scope() as session:
acc = Account(chain_id="ait-mainnet", address="aitbc1genesis", balance=10000000, nonce=0, updated_at=datetime.utcnow(), account_type="regular", metadata="{}")
session.merge(acc)
session.commit()
print("Added aitbc1genesis to mainnet")
if __name__ == "__main__":
fix()

View File

@@ -0,0 +1,27 @@
import sqlite3
def fix():
try:
conn = sqlite3.connect('/opt/aitbc/data/ait-mainnet/chain.db')
cur = conn.cursor()
cur.execute('PRAGMA table_info("block")')
columns = [col[1] for col in cur.fetchall()]
if 'metadata' in columns:
print("Renaming metadata column to block_metadata...")
cur.execute('ALTER TABLE "block" RENAME COLUMN metadata TO block_metadata')
conn.commit()
elif 'block_metadata' not in columns:
print("Adding block_metadata column...")
cur.execute('ALTER TABLE "block" ADD COLUMN block_metadata TEXT')
conn.commit()
else:
print("block_metadata column already exists.")
conn.close()
except Exception as e:
print(f"Error modifying database: {e}")
if __name__ == "__main__":
fix()

View File

@@ -0,0 +1,39 @@
import sqlite3
def fix():
try:
conn = sqlite3.connect('/opt/aitbc/data/chain.db')
cur = conn.cursor()
cur.execute('PRAGMA table_info("block")')
columns = [col[1] for col in cur.fetchall()]
if 'metadata' in columns:
print("Renaming metadata column to block_metadata in default db...")
cur.execute('ALTER TABLE "block" RENAME COLUMN metadata TO block_metadata')
conn.commit()
elif 'block_metadata' not in columns:
print("Adding block_metadata column to default db...")
cur.execute('ALTER TABLE "block" ADD COLUMN block_metadata TEXT')
conn.commit()
else:
print("block_metadata column already exists in default db.")
cur.execute('PRAGMA table_info("transaction")')
columns = [col[1] for col in cur.fetchall()]
if 'metadata' in columns:
print("Renaming metadata column to tx_metadata in default db...")
cur.execute('ALTER TABLE "transaction" RENAME COLUMN metadata TO tx_metadata')
conn.commit()
elif 'tx_metadata' not in columns:
print("Adding tx_metadata column to default db...")
cur.execute('ALTER TABLE "transaction" ADD COLUMN tx_metadata TEXT')
conn.commit()
conn.close()
except Exception as e:
print(f"Error modifying database: {e}")
if __name__ == "__main__":
fix()

View File

@@ -0,0 +1,40 @@
from aitbc_chain.database import engine, init_db
from sqlalchemy import text
def fix():
init_db()
with engine.connect() as conn:
try:
conn.execute(text('ALTER TABLE "transaction" ADD COLUMN metadata TEXT'))
print("Added metadata")
except Exception as e:
pass
try:
conn.execute(text('ALTER TABLE "transaction" ADD COLUMN value INTEGER DEFAULT 0'))
print("Added value")
except Exception as e:
pass
try:
conn.execute(text('ALTER TABLE "transaction" ADD COLUMN fee INTEGER DEFAULT 0'))
print("Added fee")
except Exception as e:
pass
try:
conn.execute(text('ALTER TABLE "transaction" ADD COLUMN nonce INTEGER DEFAULT 0'))
print("Added nonce")
except Exception as e:
pass
try:
conn.execute(text('ALTER TABLE "transaction" ADD COLUMN status TEXT DEFAULT "pending"'))
print("Added status")
except Exception as e:
pass
try:
conn.execute(text('ALTER TABLE "transaction" ADD COLUMN timestamp TEXT'))
print("Added timestamp")
except Exception as e:
pass
conn.commit()
if __name__ == "__main__":
fix()

View File

@@ -0,0 +1,5 @@
from pydantic_settings import BaseSettings, SettingsConfigDict
class TestSettings(BaseSettings):
model_config = SettingsConfigDict(env_file="/opt/aitbc/.env", env_file_encoding="utf-8", case_sensitive=False, extra="ignore")
db_path: str = ""
print(TestSettings().db_path)

View File

@@ -0,0 +1,27 @@
import sqlite3
def fix():
try:
conn = sqlite3.connect('/opt/aitbc/data/ait-mainnet/chain.db')
cur = conn.cursor()
cur.execute('PRAGMA table_info("transaction")')
columns = [col[1] for col in cur.fetchall()]
if 'metadata' in columns:
print("Renaming metadata column to tx_metadata...")
cur.execute('ALTER TABLE "transaction" RENAME COLUMN metadata TO tx_metadata')
conn.commit()
elif 'tx_metadata' not in columns:
print("Adding tx_metadata column...")
cur.execute('ALTER TABLE "transaction" ADD COLUMN tx_metadata TEXT')
conn.commit()
else:
print("tx_metadata column already exists.")
conn.close()
except Exception as e:
print(f"Error modifying database: {e}")
if __name__ == "__main__":
fix()

View File

@@ -0,0 +1,50 @@
import sqlite3
def fix_db():
print("Fixing transaction table on aitbc node...")
conn = sqlite3.connect('/opt/aitbc/data/ait-mainnet/chain.db')
cursor = conn.cursor()
try:
cursor.execute('ALTER TABLE "transaction" ADD COLUMN nonce INTEGER DEFAULT 0;')
print("Added nonce column")
except sqlite3.OperationalError as e:
print(f"Error adding nonce: {e}")
try:
cursor.execute('ALTER TABLE "transaction" ADD COLUMN value INTEGER DEFAULT 0;')
print("Added value column")
except sqlite3.OperationalError as e:
print(f"Error adding value: {e}")
try:
cursor.execute('ALTER TABLE "transaction" ADD COLUMN fee INTEGER DEFAULT 0;')
print("Added fee column")
except sqlite3.OperationalError as e:
print(f"Error adding fee: {e}")
try:
cursor.execute('ALTER TABLE "transaction" ADD COLUMN status TEXT DEFAULT "pending";')
print("Added status column")
except sqlite3.OperationalError as e:
print(f"Error adding status: {e}")
try:
cursor.execute('ALTER TABLE "transaction" ADD COLUMN tx_metadata TEXT;')
print("Added tx_metadata column")
except sqlite3.OperationalError as e:
print(f"Error adding tx_metadata: {e}")
try:
cursor.execute('ALTER TABLE "transaction" ADD COLUMN timestamp TEXT;')
print("Added timestamp column")
except sqlite3.OperationalError as e:
print(f"Error adding timestamp: {e}")
conn.commit()
conn.close()
print("Done fixing transaction table.")
if __name__ == '__main__':
fix_db()

View File

@@ -0,0 +1,2 @@
from aitbc_chain.config import settings
print(settings.db_path)

View File

@@ -32,6 +32,9 @@ class RateLimitMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next): async def dispatch(self, request: Request, call_next):
client_ip = request.client.host if request.client else "unknown" 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() now = time.time()
# Clean old entries # Clean old entries
self._requests[client_ip] = [ self._requests[client_ip] = [
@@ -109,7 +112,8 @@ def create_app() -> FastAPI:
# Middleware (applied in reverse order) # Middleware (applied in reverse order)
app.add_middleware(RequestLoggingMiddleware) 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( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=[ 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

@@ -16,11 +16,11 @@ class ProposerConfig(BaseModel):
max_txs_per_block: int max_txs_per_block: int
class ChainSettings(BaseSettings): class ChainSettings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", case_sensitive=False) model_config = SettingsConfigDict(env_file="/opt/aitbc/.env", env_file_encoding="utf-8", case_sensitive=False, extra="ignore")
chain_id: str = "ait-devnet" chain_id: str = ""
supported_chains: str = "ait-devnet" # Comma-separated list of supported chain IDs supported_chains: str = "ait-devnet" # Comma-separated list of supported chain IDs
db_path: Path = Path("./data/chain.db") db_path: Path = Path("/opt/aitbc/data/chain.db")
rpc_bind_host: str = "127.0.0.1" rpc_bind_host: str = "127.0.0.1"
rpc_bind_port: int = 8080 rpc_bind_port: int = 8080
@@ -28,7 +28,7 @@ class ChainSettings(BaseSettings):
p2p_bind_host: str = "127.0.0.2" p2p_bind_host: str = "127.0.0.2"
p2p_bind_port: int = 7070 p2p_bind_port: int = 7070
proposer_id: str = "ait-devnet-proposer" proposer_id: str = ""
proposer_key: Optional[str] = None proposer_key: Optional[str] = None
mint_per_unit: int = 0 # No new minting after genesis for production 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_time_seconds: int = 2
# Block production toggle (set false on followers)
enable_block_production: bool = True
# Block production limits # Block production limits
max_block_size_bytes: int = 1_000_000 # 1 MB max_block_size_bytes: int = 1_000_000 # 1 MB
max_txs_per_block: int = 500 max_txs_per_block: int = 500

View File

@@ -120,11 +120,11 @@ class PoAProposer:
return return
async def _propose_block(self) -> None: async def _propose_block(self) -> None:
# Check internal mempool # Check internal mempool and include transactions
from ..mempool import get_mempool from ..mempool import get_mempool
if get_mempool().size(self._config.chain_id) == 0: from ..models import Transaction, Account
return mempool = get_mempool()
with self._session_factory() as session: 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() head = session.exec(select(Block).where(Block.chain_id == self._config.chain_id).order_by(Block.height.desc()).limit(1)).first()
next_height = 0 next_height = 0
@@ -136,7 +136,72 @@ class PoAProposer:
interval_seconds = (datetime.utcnow() - head.timestamp).total_seconds() interval_seconds = (datetime.utcnow() - head.timestamp).total_seconds()
timestamp = datetime.utcnow() 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, 'ait-mainnet')
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,
payload=tx_data,
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( block = Block(
chain_id=self._config.chain_id, chain_id=self._config.chain_id,
@@ -145,7 +210,7 @@ class PoAProposer:
parent_hash=parent_hash, parent_hash=parent_hash,
proposer=self._config.proposer_id, proposer=self._config.proposer_id,
timestamp=timestamp, timestamp=timestamp,
tx_count=0, tx_count=len(processed_txs),
state_root=None, state_root=None,
) )
session.add(block) session.add(block)
@@ -173,6 +238,7 @@ class PoAProposer:
) )
# Broadcast the new block # Broadcast the new block
tx_list = [tx.content for tx in processed_txs] if processed_txs else []
await gossip_broker.publish( await gossip_broker.publish(
"blocks", "blocks",
{ {
@@ -184,7 +250,8 @@ class PoAProposer:
"timestamp": block.timestamp.isoformat(), "timestamp": block.timestamp.isoformat(),
"tx_count": block.tx_count, "tx_count": block.tx_count,
"state_root": block.state_root, "state_root": block.state_root,
} "transactions": tx_list,
},
) )
async def _ensure_genesis_block(self) -> None: async def _ensure_genesis_block(self) -> None:
@@ -258,6 +325,11 @@ class PoAProposer:
with self._session_factory() as session: with self._session_factory() as session:
return session.exec(select(Block).order_by(Block.height.desc()).limit(1)).first() 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: def _compute_block_hash(self, height: int, parent_hash: str, timestamp: datetime, transactions: list = None) -> str:
payload = f"{self._config.chain_id}|{height}|{parent_hash}|{timestamp.isoformat()}".encode() # 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() return "0x" + hashlib.sha256(payload).hexdigest()

View File

@@ -4,15 +4,15 @@ import asyncio
import json import json
import warnings import warnings
from collections import defaultdict from collections import defaultdict
from contextlib import suppress from contextlib import suppress, asynccontextmanager
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Set from typing import Any, Callable, Dict, List, Optional, Set
warnings.filterwarnings("ignore", message="coroutine.* was never awaited", category=RuntimeWarning) warnings.filterwarnings("ignore", message="coroutine.* was never awaited", category=RuntimeWarning)
try: try:
from starlette.broadcast import Broadcast from broadcaster import Broadcast
except ImportError: # pragma: no cover - Starlette removed Broadcast in recent versions except ImportError: # pragma: no cover
Broadcast = None # type: ignore[assignment] Broadcast = None # type: ignore[assignment]
from ..metrics import metrics_registry from ..metrics import metrics_registry
@@ -225,25 +225,15 @@ class GossipBroker:
class _InProcessSubscriber: class _InProcessSubscriber:
def __init__(self, queue: "asyncio.Queue[Any]", release: Callable[[], None]): def __init__(self, queue: "asyncio.Queue[Any]"):
self._queue = queue self._queue = queue
self._release = release
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb):
self._release()
def __aiter__(self): # type: ignore[override] def __aiter__(self): # type: ignore[override]
return self._iterator() return self._iterator()
async def _iterator(self): async def _iterator(self):
try: while True:
while True: yield await self._queue.get()
yield await self._queue.get()
finally:
self._release()
class _InProcessBroadcast: class _InProcessBroadcast:
@@ -262,23 +252,19 @@ class _InProcessBroadcast:
self._topics.clear() self._topics.clear()
self._running = False self._running = False
async def subscribe(self, topic: str) -> _InProcessSubscriber: @asynccontextmanager
async def subscribe(self, topic: str):
queue: "asyncio.Queue[Any]" = asyncio.Queue() queue: "asyncio.Queue[Any]" = asyncio.Queue()
async with self._lock: async with self._lock:
self._topics[topic].append(queue) self._topics[topic].append(queue)
def release() -> None: try:
async def _remove() -> None: yield _InProcessSubscriber(queue)
async with self._lock: finally:
queues = self._topics.get(topic) async with self._lock:
if queues and queue in queues: queues = self._topics.get(topic)
queues.remove(queue) if queues and queue in queues:
if not queues: queues.remove(queue)
self._topics.pop(topic, None)
asyncio.create_task(_remove())
return _InProcessSubscriber(queue, release)
async def publish(self, topic: str, message: Any) -> None: async def publish(self, topic: str, message: Any) -> None:
if not self._running: if not self._running:

View File

@@ -0,0 +1,307 @@
from __future__ import annotations
import asyncio
import json
import warnings
from collections import defaultdict
from contextlib import suppress
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Set
warnings.filterwarnings("ignore", message="coroutine.* was never awaited", category=RuntimeWarning)
try:
from broadcaster import Broadcast
except ImportError: # pragma: no cover
Broadcast = None # type: ignore[assignment]
from ..metrics import metrics_registry
def _increment_publication(metric_prefix: str, topic: str) -> None:
metrics_registry.increment(f"{metric_prefix}_total")
metrics_registry.increment(f"{metric_prefix}_topic_{topic}")
def _set_queue_gauge(topic: str, size: int) -> None:
metrics_registry.set_gauge(f"gossip_queue_size_{topic}", float(size))
def _update_subscriber_metrics(topics: Dict[str, List["asyncio.Queue[Any]"]]) -> None:
for topic, queues in topics.items():
metrics_registry.set_gauge(f"gossip_subscribers_topic_{topic}", float(len(queues)))
total = sum(len(queues) for queues in topics.values())
metrics_registry.set_gauge("gossip_subscribers_total", float(total))
def _clear_topic_metrics(topic: str) -> None:
metrics_registry.set_gauge(f"gossip_subscribers_topic_{topic}", 0.0)
_set_queue_gauge(topic, 0)
@dataclass
class TopicSubscription:
topic: str
queue: "asyncio.Queue[Any]"
_unsubscribe: Callable[[], None]
def close(self) -> None:
self._unsubscribe()
async def get(self) -> Any:
return await self.queue.get()
async def __aiter__(self): # type: ignore[override]
try:
while True:
yield await self.queue.get()
finally:
self.close()
class GossipBackend:
async def start(self) -> None: # pragma: no cover - overridden as needed
return None
async def publish(self, topic: str, message: Any) -> None:
raise NotImplementedError
async def subscribe(self, topic: str, max_queue_size: int = 100) -> TopicSubscription:
raise NotImplementedError
async def shutdown(self) -> None:
return None
class InMemoryGossipBackend(GossipBackend):
def __init__(self) -> None:
self._topics: Dict[str, List["asyncio.Queue[Any]"]] = defaultdict(list)
self._lock = asyncio.Lock()
async def publish(self, topic: str, message: Any) -> None:
async with self._lock:
queues = list(self._topics.get(topic, []))
for queue in queues:
await queue.put(message)
_set_queue_gauge(topic, queue.qsize())
_increment_publication("gossip_publications", topic)
async def subscribe(self, topic: str, max_queue_size: int = 100) -> TopicSubscription:
queue: "asyncio.Queue[Any]" = asyncio.Queue(maxsize=max_queue_size)
async with self._lock:
self._topics[topic].append(queue)
_update_subscriber_metrics(self._topics)
_set_queue_gauge(topic, queue.qsize())
def _unsubscribe() -> None:
async def _remove() -> None:
async with self._lock:
queues = self._topics.get(topic)
if queues is None:
return
if queue in queues:
queues.remove(queue)
if not queues:
self._topics.pop(topic, None)
_clear_topic_metrics(topic)
_update_subscriber_metrics(self._topics)
asyncio.create_task(_remove())
return TopicSubscription(topic=topic, queue=queue, _unsubscribe=_unsubscribe)
async def shutdown(self) -> None:
async with self._lock:
topics = list(self._topics.keys())
self._topics.clear()
for topic in topics:
_clear_topic_metrics(topic)
_update_subscriber_metrics(self._topics)
class BroadcastGossipBackend(GossipBackend):
def __init__(self, url: str) -> None:
if Broadcast is None: # provide in-process fallback when Broadcast is missing
self._broadcast = _InProcessBroadcast()
else:
self._broadcast = Broadcast(url) # type: ignore[arg-type]
self._tasks: Set[asyncio.Task[None]] = set()
self._lock = asyncio.Lock()
self._running = False
async def start(self) -> None:
if not self._running:
await self._broadcast.connect() # type: ignore[union-attr]
self._running = True
async def publish(self, topic: str, message: Any) -> None:
if not self._running:
raise RuntimeError("Broadcast backend not started")
payload = _encode_message(message)
await self._broadcast.publish(topic, payload) # type: ignore[union-attr]
_increment_publication("gossip_broadcast_publications", topic)
async def subscribe(self, topic: str, max_queue_size: int = 100) -> TopicSubscription:
if not self._running:
raise RuntimeError("Broadcast backend not started")
queue: "asyncio.Queue[Any]" = asyncio.Queue(maxsize=max_queue_size)
stop_event = asyncio.Event()
async def _run_subscription() -> None:
async with self._broadcast.subscribe(topic) as subscriber: # type: ignore[attr-defined,union-attr]
async for event in subscriber: # type: ignore[union-attr]
if stop_event.is_set():
break
data = _decode_message(getattr(event, "message", event))
try:
await queue.put(data)
_set_queue_gauge(topic, queue.qsize())
except asyncio.CancelledError:
break
task = asyncio.create_task(_run_subscription(), name=f"broadcast-sub:{topic}")
async with self._lock:
self._tasks.add(task)
metrics_registry.set_gauge("gossip_broadcast_subscribers_total", float(len(self._tasks)))
def _unsubscribe() -> None:
async def _stop() -> None:
stop_event.set()
task.cancel()
with suppress(asyncio.CancelledError):
await task
async with self._lock:
self._tasks.discard(task)
metrics_registry.set_gauge("gossip_broadcast_subscribers_total", float(len(self._tasks)))
asyncio.create_task(_stop())
return TopicSubscription(topic=topic, queue=queue, _unsubscribe=_unsubscribe)
async def shutdown(self) -> None:
async with self._lock:
tasks = list(self._tasks)
self._tasks.clear()
metrics_registry.set_gauge("gossip_broadcast_subscribers_total", 0.0)
for task in tasks:
task.cancel()
with suppress(asyncio.CancelledError):
await task
if self._running:
await self._broadcast.disconnect() # type: ignore[union-attr]
self._running = False
class GossipBroker:
def __init__(self, backend: GossipBackend) -> None:
self._backend = backend
self._lock = asyncio.Lock()
self._started = False
async def publish(self, topic: str, message: Any) -> None:
if not self._started:
await self._backend.start()
self._started = True
await self._backend.publish(topic, message)
async def subscribe(self, topic: str, max_queue_size: int = 100) -> TopicSubscription:
if not self._started:
await self._backend.start()
self._started = True
return await self._backend.subscribe(topic, max_queue_size=max_queue_size)
async def set_backend(self, backend: GossipBackend) -> None:
await backend.start()
async with self._lock:
previous = self._backend
self._backend = backend
self._started = True
await previous.shutdown()
async def shutdown(self) -> None:
await self._backend.shutdown()
class _InProcessSubscriber:
def __init__(self, queue: "asyncio.Queue[Any]"):
self._queue = queue
def __aiter__(self): # type: ignore[override]
return self._iterator()
async def _iterator(self):
while True:
yield await self._queue.get()
class _InProcessBroadcast:
"""Minimal in-memory broadcast substitute for tests when Starlette Broadcast is absent."""
def __init__(self) -> None:
self._topics: Dict[str, List["asyncio.Queue[Any]"]] = defaultdict(list)
self._lock = asyncio.Lock()
self._running = False
async def connect(self) -> None:
self._running = True
async def disconnect(self) -> None:
async with self._lock:
self._topics.clear()
self._running = False
@asynccontextmanager
async def subscribe(self, topic: str):
queue: "asyncio.Queue[Any]" = asyncio.Queue()
async with self._lock:
self._topics[topic].append(queue)
try:
yield _InProcessSubscriber(queue)
finally:
async with self._lock:
queues = self._topics.get(topic)
if queues and queue in queues:
queues.remove(queue)
async def publish(self, topic: str, message: Any) -> None:
if not self._running:
raise RuntimeError("Broadcast backend not started")
async with self._lock:
queues = list(self._topics.get(topic, []))
for queue in queues:
await queue.put(message)
def create_backend(backend_type: str, *, broadcast_url: Optional[str] = None) -> GossipBackend:
backend = backend_type.lower()
if backend in {"memory", "inmemory", "local"}:
return InMemoryGossipBackend()
if backend in {"broadcast", "starlette", "redis"}:
if not broadcast_url:
raise ValueError("Broadcast backend requires a gossip_broadcast_url setting")
return BroadcastGossipBackend(broadcast_url)
raise ValueError(f"Unsupported gossip backend '{backend_type}'")
def _encode_message(message: Any) -> Any:
if isinstance(message, (str, bytes, bytearray)):
return message
return json.dumps(message, separators=(",", ":"))
def _decode_message(message: Any) -> Any:
if isinstance(message, (bytes, bytearray)):
message = message.decode("utf-8")
if isinstance(message, str):
try:
return json.loads(message)
except json.JSONDecodeError:
return message
return message
gossip_broker = GossipBroker(InMemoryGossipBackend())

View File

@@ -103,7 +103,7 @@ class BlockchainNode:
if isinstance(tx_data, str): if isinstance(tx_data, str):
import json import json
tx_data = json.loads(tx_data) 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) mempool.add(tx_data, chain_id=chain_id)
except Exception as exc: except Exception as exc:
logger.error(f"Error processing transaction from gossip: {exc}") logger.error(f"Error processing transaction from gossip: {exc}")
@@ -121,10 +121,10 @@ class BlockchainNode:
if isinstance(block_data, str): if isinstance(block_data, str):
import json import json
block_data = json.loads(block_data) 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')}") logger.info(f"Importing block for chain {chain_id}: {block_data.get('height')}")
sync = ChainSync(session_factory=session_scope, chain_id=chain_id) sync = ChainSync(session_factory=session_scope, chain_id=chain_id)
res = sync.import_block(block_data) res = sync.import_block(block_data, transactions=block_data.get("transactions"))
logger.info(f"Import result: accepted={res.accepted}, reason={res.reason}") logger.info(f"Import result: accepted={res.accepted}, reason={res.reason}")
except Exception as exc: except Exception as exc:
logger.error(f"Error processing block from gossip: {exc}") logger.error(f"Error processing block from gossip: {exc}")
@@ -148,7 +148,11 @@ class BlockchainNode:
max_size=settings.mempool_max_size, max_size=settings.mempool_max_size,
min_fee=settings.min_fee, 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() await self._setup_gossip_subscribers()
try: try:
await self._stop_event.wait() await self._stop_event.wait()

View File

@@ -38,7 +38,10 @@ class InMemoryMempool:
self._max_size = max_size self._max_size = max_size
self._min_fee = min_fee 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) fee = tx.get("fee", 0)
if fee < self._min_fee: if fee < self._min_fee:
raise ValueError(f"Fee {fee} below minimum {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}") metrics_registry.increment(f"mempool_tx_added_total_{chain_id}")
return tx_hash 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: with self._lock:
return list(self._transactions.values()) 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).""" """Drain transactions for block inclusion, prioritized by fee (highest first)."""
with self._lock: with self._lock:
sorted_txs = sorted( sorted_txs = sorted(
@@ -87,14 +96,20 @@ class InMemoryMempool:
metrics_registry.increment(f"mempool_tx_drained_total_{chain_id}", float(len(result))) metrics_registry.increment(f"mempool_tx_drained_total_{chain_id}", float(len(result)))
return 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: with self._lock:
removed = self._transactions.pop(tx_hash, None) is not None removed = self._transactions.pop(tx_hash, None) is not None
if removed: if removed:
metrics_registry.set_gauge("mempool_size", float(len(self._transactions))) metrics_registry.set_gauge("mempool_size", float(len(self._transactions)))
return removed 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: with self._lock:
return len(self._transactions) 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.execute("CREATE INDEX IF NOT EXISTS idx_mempool_fee ON mempool(fee DESC)")
self._conn.commit() 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) fee = tx.get("fee", 0)
if fee < self._min_fee: if fee < self._min_fee:
raise ValueError(f"Fee {fee} below minimum {self._min_fee}") raise ValueError(f"Fee {fee} below minimum {self._min_fee}")
@@ -169,7 +187,10 @@ class DatabaseMempool:
self._update_gauge(chain_id) self._update_gauge(chain_id)
return tx_hash 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: with self._lock:
rows = self._conn.execute( 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", "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 ) 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: with self._lock:
rows = self._conn.execute( 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", "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) self._update_gauge(chain_id)
return 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: with self._lock:
cursor = self._conn.execute("DELETE FROM mempool WHERE chain_id = ? AND tx_hash = ?", (chain_id, tx_hash)) cursor = self._conn.execute("DELETE FROM mempool WHERE chain_id = ? AND tx_hash = ?", (chain_id, tx_hash))
self._conn.commit() self._conn.commit()
@@ -223,11 +250,17 @@ class DatabaseMempool:
self._update_gauge(chain_id) self._update_gauge(chain_id)
return removed 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: with self._lock:
return self._conn.execute("SELECT COUNT(*) FROM mempool WHERE chain_id = ?", (chain_id,)).fetchone()[0] 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] 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)) metrics_registry.set_gauge(f"mempool_size_{chain_id}", float(count))

View File

@@ -36,6 +36,7 @@ class Block(SQLModel, table=True):
timestamp: datetime = Field(default_factory=datetime.utcnow, index=True) timestamp: datetime = Field(default_factory=datetime.utcnow, index=True)
tx_count: int = 0 tx_count: int = 0
state_root: Optional[str] = None state_root: Optional[str] = None
block_metadata: Optional[str] = Field(default=None)
# Relationships - use sa_relationship_kwargs for lazy loading # Relationships - use sa_relationship_kwargs for lazy loading
transactions: List["Transaction"] = Relationship( transactions: List["Transaction"] = Relationship(
@@ -90,6 +91,14 @@ class Transaction(SQLModel, table=True):
) )
created_at: datetime = Field(default_factory=datetime.utcnow, index=True) created_at: datetime = Field(default_factory=datetime.utcnow, index=True)
# New fields added to schema
nonce: int = Field(default=0)
value: int = Field(default=0)
fee: int = Field(default=0)
status: str = Field(default="pending")
timestamp: Optional[str] = Field(default=None)
tx_metadata: Optional[str] = Field(default=None)
# Relationship # Relationship
block: Optional["Block"] = Relationship( block: Optional["Block"] = Relationship(
back_populates="transactions", back_populates="transactions",

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() 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]: def _serialize_receipt(receipt: Receipt) -> Dict[str, Any]:
return { return {
@@ -63,7 +70,14 @@ class EstimateFeeRequest(BaseModel):
@router.get("/head", summary="Get current chain head") @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") metrics_registry.increment("rpc_get_head_total")
start = time.perf_counter() start = time.perf_counter()
with session_scope() as session: with session_scope() as session:
@@ -91,14 +105,24 @@ async def get_block(height: int) -> Dict[str, Any]:
metrics_registry.increment("rpc_get_block_not_found_total") metrics_registry.increment("rpc_get_block_not_found_total")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="block not found") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="block not found")
metrics_registry.increment("rpc_get_block_success_total") metrics_registry.increment("rpc_get_block_success_total")
txs = session.exec(select(Transaction).where(Transaction.block_height == height)).all()
tx_list = []
for tx in txs:
t = dict(tx.payload) if tx.payload else {}
t["tx_hash"] = tx.tx_hash
tx_list.append(t)
metrics_registry.observe("rpc_get_block_duration_seconds", time.perf_counter() - start) metrics_registry.observe("rpc_get_block_duration_seconds", time.perf_counter() - start)
return { return {
"height": block.height, "height": block.height,
"hash": block.hash, "hash": block.hash,
"parent_hash": block.parent_hash, "parent_hash": block.parent_hash,
"proposer": block.proposer,
"timestamp": block.timestamp.isoformat(), "timestamp": block.timestamp.isoformat(),
"tx_count": block.tx_count, "tx_count": block.tx_count,
"state_root": block.state_root, "state_root": block.state_root,
"transactions": tx_list,
} }
@@ -136,13 +160,22 @@ async def get_blocks_range(start: int, end: int) -> Dict[str, Any]:
# Serialize blocks # Serialize blocks
block_list = [] block_list = []
for block in blocks: for block in blocks:
txs = session.exec(select(Transaction).where(Transaction.block_height == block.height)).all()
tx_list = []
for tx in txs:
t = dict(tx.payload) if tx.payload else {}
t["tx_hash"] = tx.tx_hash
tx_list.append(t)
block_list.append({ block_list.append({
"height": block.height, "height": block.height,
"hash": block.hash, "hash": block.hash,
"parent_hash": block.parent_hash, "parent_hash": block.parent_hash,
"proposer": block.proposer,
"timestamp": block.timestamp.isoformat(), "timestamp": block.timestamp.isoformat(),
"tx_count": block.tx_count, "tx_count": block.tx_count,
"state_root": block.state_root, "state_root": block.state_root,
"transactions": tx_list,
}) })
metrics_registry.increment("rpc_get_blocks_range_success_total") metrics_registry.increment("rpc_get_blocks_range_success_total")
@@ -157,7 +190,8 @@ async def get_blocks_range(start: int, end: int) -> Dict[str, Any]:
@router.get("/tx/{tx_hash}", summary="Get transaction by hash") @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") metrics_registry.increment("rpc_get_transaction_total")
start = time.perf_counter() start = time.perf_counter()
with session_scope() as session: with session_scope() as session:
@@ -296,7 +330,8 @@ async def get_receipts(limit: int = 20, offset: int = 0) -> Dict[str, Any]:
@router.get("/getBalance/{address}", summary="Get account balance") @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") metrics_registry.increment("rpc_get_balance_total")
start = time.perf_counter() start = time.perf_counter()
with session_scope() as session: with session_scope() as session:
@@ -442,13 +477,13 @@ async def get_addresses(limit: int = 20, offset: int = 0, min_balance: int = 0)
@router.post("/sendTx", summary="Submit a new transaction") @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") metrics_registry.increment("rpc_send_tx_total")
start = time.perf_counter() start = time.perf_counter()
mempool = get_mempool() mempool = get_mempool()
tx_dict = request.model_dump() tx_dict = request.model_dump()
try: try:
tx_hash = mempool.add(tx_dict, chain_id=chain_id) tx_hash = mempool.add(tx_dict, chain_id=chain_id or request.payload.get('chain_id') or 'ait-mainnet')
except ValueError as e: except ValueError as e:
metrics_registry.increment("rpc_send_tx_rejected_total") metrics_registry.increment("rpc_send_tx_rejected_total")
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@@ -481,7 +516,7 @@ async def send_transaction(request: TransactionRequest, chain_id: str = "ait-dev
@router.post("/submitReceipt", summary="Submit receipt claim transaction") @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") metrics_registry.increment("rpc_submit_receipt_total")
start = time.perf_counter() start = time.perf_counter()
tx_payload = { tx_payload = {
@@ -539,7 +574,7 @@ class ImportBlockRequest(BaseModel):
@router.post("/importBlock", summary="Import a block from a remote peer") @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 ..sync import ChainSync, ProposerSignatureValidator
from ..config import settings as cfg from ..config import settings as cfg
@@ -578,7 +613,7 @@ async def import_block(request: ImportBlockRequest, chain_id: str = "ait-devnet"
@router.get("/syncStatus", summary="Get chain sync status") @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 ..sync import ChainSync
from ..config import settings as cfg from ..config import settings as cfg
@@ -588,7 +623,7 @@ async def sync_status(chain_id: str = "ait-devnet") -> Dict[str, Any]:
@router.get("/info", summary="Get blockchain information") @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""" """Get comprehensive blockchain information"""
from ..config import settings as cfg from ..config import settings as cfg
@@ -634,31 +669,48 @@ async def get_blockchain_info(chain_id: str = "ait-devnet") -> Dict[str, Any]:
@router.get("/supply", summary="Get token supply information") @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""" """Get token supply information"""
from ..config import settings as cfg from ..config import settings as cfg
from ..models import Account
chain_id = get_chain_id(chain_id)
metrics_registry.increment("rpc_supply_total") metrics_registry.increment("rpc_supply_total")
start = time.perf_counter() start = time.perf_counter()
with session_scope() as session: with session_scope() as session:
# Simple implementation for now # Calculate actual values from database
response = { accounts = session.exec(select(Account).where(Account.chain_id == chain_id)).all()
"chain_id": chain_id, total_balance = sum(account.balance for account in accounts)
"total_supply": 1000000000, # 1 billion from genesis total_accounts = len(accounts)
"circulating_supply": 0, # No transactions yet
"faucet_balance": 1000000000, # All tokens in faucet # Production implementation - calculate real circulating supply
"faucet_address": "ait1faucet000000000000000000000000000000000", if chain_id == "ait-mainnet":
"mint_per_unit": cfg.mint_per_unit, response = {
"total_accounts": 0 "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) metrics_registry.observe("rpc_supply_duration_seconds", time.perf_counter() - start)
return response return response
@router.get("/validators", summary="List blockchain validators") @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)""" """List blockchain validators (authorities)"""
from ..config import settings as cfg from ..config import settings as cfg
@@ -690,7 +742,7 @@ async def get_validators(chain_id: str = "ait-devnet") -> Dict[str, Any]:
@router.get("/state", summary="Get blockchain state information") @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""" """Get blockchain state information for a chain"""
start = time.perf_counter() start = time.perf_counter()
@@ -710,7 +762,7 @@ async def get_chain_state(chain_id: str = "ait-devnet"):
@router.get("/rpc/getBalance/{address}", summary="Get account balance") @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""" """Get account balance for a specific address"""
start = time.perf_counter() start = time.perf_counter()
@@ -753,7 +805,7 @@ async def get_balance(address: str, chain_id: str = "ait-devnet"):
@router.get("/rpc/head", summary="Get current chain head") @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""" """Get current chain head block"""
start = time.perf_counter() start = time.perf_counter()
@@ -799,7 +851,7 @@ async def get_head(chain_id: str = "ait-devnet"):
@router.get("/rpc/transactions", summary="Get latest transactions") @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""" """Get latest transactions"""
start = time.perf_counter() start = time.perf_counter()

View File

@@ -16,7 +16,7 @@ from sqlmodel import Session, select
from .config import settings from .config import settings
from .logger import get_logger from .logger import get_logger
from .metrics import metrics_registry from .metrics import metrics_registry
from .models import Block, Transaction from .models import Block, Transaction, Account
logger = get_logger(__name__) logger = get_logger(__name__)
@@ -284,15 +284,45 @@ class ChainSync:
) )
session.add(block) session.add(block)
# Import transactions if provided # Import transactions if provided and apply state changes
if transactions: if transactions:
for tx_data in 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( tx = Transaction(
chain_id=self._chain_id, chain_id=self._chain_id,
tx_hash=tx_data.get("tx_hash", ""), tx_hash=tx_hash,
block_height=block_data["height"], block_height=block_data["height"],
sender=tx_data.get("sender", ""), sender=sender_addr,
recipient=tx_data.get("recipient", ""), recipient=recipient_addr,
payload=tx_data, payload=tx_data,
) )
session.add(tx) session.add(tx)

View File

@@ -0,0 +1,5 @@
from aitbc_chain.config import settings
from aitbc_chain.mempool import init_mempool, get_mempool
init_mempool(backend=settings.mempool_backend, db_path=str(settings.db_path.parent / "mempool.db"), max_size=settings.mempool_max_size, min_fee=settings.min_fee)
pool = get_mempool()
print(pool.__class__.__name__)

View File

@@ -0,0 +1,3 @@
from aitbc_chain.config import settings
import sys
print(settings.db_path.parent / "mempool.db")

View File

@@ -0,0 +1,6 @@
from aitbc_chain.database import session_scope
from aitbc_chain.models import Account
with session_scope() as session:
acc = session.get(Account, ("ait-mainnet", "aitbc1genesis"))
print(acc.address, acc.balance)

View File

@@ -1,7 +1,7 @@
APP_ENV=dev APP_ENV=dev
APP_HOST=127.0.0.1 APP_HOST=127.0.0.1
APP_PORT=8011 APP_PORT=8011
DATABASE_URL=sqlite:///./data/coordinator.db DATABASE_URL=sqlite:////opt/aitbc/data/coordinator.db
CLIENT_API_KEYS=${CLIENT_API_KEY},client_dev_key_2 CLIENT_API_KEYS=${CLIENT_API_KEY},client_dev_key_2
MINER_API_KEYS=${MINER_API_KEY},miner_dev_key_2 MINER_API_KEYS=${MINER_API_KEY},miner_dev_key_2
ADMIN_API_KEYS=${ADMIN_API_KEY} ADMIN_API_KEYS=${ADMIN_API_KEY}

View File

@@ -8,7 +8,7 @@ import json
from decimal import Decimal from decimal import Decimal
# Database configurations # Database configurations
SQLITE_DB = "coordinator.db" SQLITE_DB = "/opt/aitbc/data/coordinator.db"
PG_CONFIG = { PG_CONFIG = {
"host": "localhost", "host": "localhost",
"database": "aitbc_coordinator", "database": "aitbc_coordinator",

View File

@@ -16,7 +16,7 @@ from decimal import Decimal
import json import json
# Database configurations # Database configurations
SQLITE_DB = "coordinator.db" SQLITE_DB = "/opt/aitbc/data/coordinator.db"
PG_CONFIG = { PG_CONFIG = {
"host": "localhost", "host": "localhost",
"database": "aitbc_coordinator", "database": "aitbc_coordinator",

View File

@@ -30,7 +30,7 @@ class DatabaseConfig(BaseSettings):
# Default SQLite path - consistent with blockchain-node pattern # Default SQLite path - consistent with blockchain-node pattern
if self.adapter == "sqlite": if self.adapter == "sqlite":
return "sqlite:///./data/coordinator.db" return "sqlite:////opt/aitbc/data/coordinator.db"
# Default PostgreSQL connection string # Default PostgreSQL connection string
return f"{self.adapter}://localhost:5432/coordinator" return f"{self.adapter}://localhost:5432/coordinator"
@@ -187,7 +187,7 @@ class Settings(BaseSettings):
if self.database.url: if self.database.url:
return self.database.url return self.database.url
# Default SQLite path - consistent with blockchain-node pattern # Default SQLite path - consistent with blockchain-node pattern
return "sqlite:///./data/coordinator.db" return "sqlite:////opt/aitbc/data/coordinator.db"
@database_url.setter @database_url.setter
def database_url(self, value: str): def database_url(self, value: str):

View File

@@ -2,13 +2,14 @@
from sqlmodel import create_engine, SQLModel from sqlmodel import create_engine, SQLModel
from sqlalchemy import StaticPool from sqlalchemy import StaticPool
from .config import settings
# Create in-memory SQLite database for now # Create database engine using URL from config
engine = create_engine( engine = create_engine(
"sqlite:///./data/coordinator.db", settings.database_url,
connect_args={"check_same_thread": False}, connect_args={"check_same_thread": False} if settings.database_url.startswith("sqlite") else {},
poolclass=StaticPool, poolclass=StaticPool if settings.database_url.startswith("sqlite") else None,
echo=True # Enable SQL logging for debugging echo=settings.test_mode # Enable SQL logging for debugging in test mode
) )

View File

@@ -48,7 +48,7 @@ async def blockchain_sync_status():
rpc_url = settings.blockchain_rpc_url.rstrip('/') rpc_url = settings.blockchain_rpc_url.rstrip('/')
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.get(f"{rpc_url}/rpc/sync", timeout=5.0) response = await client.get(f"{rpc_url}/rpc/syncStatus", timeout=5.0)
if response.status_code == 200: if response.status_code == 200:
data = response.json() data = response.json()
return { return {

View File

@@ -20,7 +20,7 @@ limiter = Limiter(key_func=get_remote_address)
router = APIRouter(tags=["marketplace"]) router = APIRouter(tags=["marketplace"])
def _get_service(session: Annotated[Session, Depends(get_session)]) -> MarketplaceService: def _get_service(session: Session = Depends(get_session)) -> MarketplaceService:
return MarketplaceService(session) return MarketplaceService(session)
@@ -33,7 +33,7 @@ def _get_service(session: Annotated[Session, Depends(get_session)]) -> Marketpla
async def list_marketplace_offers( async def list_marketplace_offers(
request: Request, request: Request,
*, *,
session: Annotated[Session, Depends(get_session)], session: Session = Depends(get_session),
status_filter: str | None = Query(default=None, alias="status", description="Filter by offer status"), status_filter: str | None = Query(default=None, alias="status", description="Filter by offer status"),
limit: int = Query(default=100, ge=1, le=500), limit: int = Query(default=100, ge=1, le=500),
offset: int = Query(default=0, ge=0), offset: int = Query(default=0, ge=0),
@@ -60,7 +60,7 @@ async def list_marketplace_offers(
async def get_marketplace_stats( async def get_marketplace_stats(
request: Request, request: Request,
*, *,
session: Annotated[Session, Depends(get_session)] session: Session = Depends(get_session)
) -> MarketplaceStatsView: ) -> MarketplaceStatsView:
marketplace_requests_total.labels(endpoint="/marketplace/stats", method="GET").inc() marketplace_requests_total.labels(endpoint="/marketplace/stats", method="GET").inc()
service = _get_service(session) service = _get_service(session)
@@ -80,7 +80,7 @@ async def get_marketplace_stats(
async def submit_marketplace_bid( async def submit_marketplace_bid(
request: Request, request: Request,
payload: MarketplaceBidRequest, payload: MarketplaceBidRequest,
session: Annotated[Session, Depends(get_session)], session: Session = Depends(get_session),
) -> dict[str, str]: ) -> dict[str, str]:
marketplace_requests_total.labels(endpoint="/marketplace/bids", method="POST").inc() marketplace_requests_total.labels(endpoint="/marketplace/bids", method="POST").inc()
service = _get_service(session) service = _get_service(session)
@@ -102,7 +102,7 @@ async def submit_marketplace_bid(
) )
async def list_marketplace_bids( async def list_marketplace_bids(
*, *,
session: Annotated[Session, Depends(get_session)], session: Session = Depends(get_session),
status_filter: str | None = Query(default=None, alias="status", description="Filter by bid status"), status_filter: str | None = Query(default=None, alias="status", description="Filter by bid status"),
provider_filter: str | None = Query(default=None, alias="provider", description="Filter by provider ID"), provider_filter: str | None = Query(default=None, alias="provider", description="Filter by provider ID"),
limit: int = Query(default=100, ge=1, le=500), limit: int = Query(default=100, ge=1, le=500),
@@ -127,7 +127,7 @@ async def list_marketplace_bids(
) )
async def get_marketplace_bid( async def get_marketplace_bid(
bid_id: str, bid_id: str,
session: Annotated[Session, Depends(get_session)], session: Session = Depends(get_session),
) -> MarketplaceBidView: ) -> MarketplaceBidView:
marketplace_requests_total.labels(endpoint="/marketplace/bids/{bid_id}", method="GET").inc() marketplace_requests_total.labels(endpoint="/marketplace/bids/{bid_id}", method="GET").inc()
service = _get_service(session) service = _get_service(session)

View File

@@ -50,7 +50,7 @@ class MarketplaceAnalyticsRequest(BaseModel):
async def create_royalty_distribution( async def create_royalty_distribution(
request: RoyaltyDistributionRequest, request: RoyaltyDistributionRequest,
offer_id: str, offer_id: str,
session: Session = Depends(Annotated[Session, Depends(get_session)]), session: Session = Depends(get_session),
current_user: str = Depends(require_admin_key()) current_user: str = Depends(require_admin_key())
): ):
"""Create royalty distribution for marketplace offer""" """Create royalty distribution for marketplace offer"""
@@ -74,7 +74,7 @@ async def create_royalty_distribution(
async def calculate_royalties( async def calculate_royalties(
offer_id: str, offer_id: str,
sale_amount: float, sale_amount: float,
session: Session = Depends(Annotated[Session, Depends(get_session)]), session: Session = Depends(get_session),
current_user: str = Depends(require_admin_key()) current_user: str = Depends(require_admin_key())
): ):
"""Calculate royalties for a sale""" """Calculate royalties for a sale"""
@@ -97,7 +97,7 @@ async def calculate_royalties(
async def create_model_license( async def create_model_license(
request: ModelLicenseRequest, request: ModelLicenseRequest,
offer_id: str, offer_id: str,
session: Session = Depends(Annotated[Session, Depends(get_session)]), session: Session = Depends(get_session),
current_user: str = Depends(require_admin_key()) current_user: str = Depends(require_admin_key())
): ):
"""Create model license for marketplace offer""" """Create model license for marketplace offer"""
@@ -123,7 +123,7 @@ async def create_model_license(
async def verify_model( async def verify_model(
request: ModelVerificationRequest, request: ModelVerificationRequest,
offer_id: str, offer_id: str,
session: Session = Depends(Annotated[Session, Depends(get_session)]), session: Session = Depends(get_session),
current_user: str = Depends(require_admin_key()) current_user: str = Depends(require_admin_key())
): ):
"""Verify model quality and performance""" """Verify model quality and performance"""
@@ -145,7 +145,7 @@ async def verify_model(
@router.post("/analytics") @router.post("/analytics")
async def get_marketplace_analytics( async def get_marketplace_analytics(
request: MarketplaceAnalyticsRequest, request: MarketplaceAnalyticsRequest,
session: Session = Depends(Annotated[Session, Depends(get_session)]), session: Session = Depends(get_session),
current_user: str = Depends(require_admin_key()) current_user: str = Depends(require_admin_key())
): ):
"""Get marketplace analytics and insights""" """Get marketplace analytics and insights"""

View File

@@ -6,7 +6,7 @@ Basic marketplace enhancement features compatible with existing domain models
import asyncio import asyncio
from aitbc.logging import get_logger from aitbc.logging import get_logger
from typing import Dict, List, Optional, Any from typing import Dict, List, Optional, Any
from datetime import datetime from datetime import datetime, timedelta
from uuid import uuid4 from uuid import uuid4
from enum import Enum from enum import Enum
@@ -225,12 +225,12 @@ class EnhancedMarketplaceService:
offers_query = select(MarketplaceOffer).where( offers_query = select(MarketplaceOffer).where(
MarketplaceOffer.created_at >= start_date MarketplaceOffer.created_at >= start_date
) )
offers = self.session.execute(offers_query).all() offers = self.session.execute(offers_query).scalars().all()
bids_query = select(MarketplaceBid).where( bids_query = select(MarketplaceBid).where(
MarketplaceBid.created_at >= start_date MarketplaceBid.submitted_at >= start_date
) )
bids = self.session.execute(bids_query).all() bids = self.session.execute(bids_query).scalars().all()
# Calculate analytics # Calculate analytics
analytics = { analytics = {
@@ -264,7 +264,7 @@ class EnhancedMarketplaceService:
if "revenue" in metrics: if "revenue" in metrics:
analytics["metrics"]["revenue"] = { analytics["metrics"]["revenue"] = {
"total_revenue": sum(bid.amount or 0 for bid in bids), "total_revenue": sum(bid.price or 0 for bid in bids),
"average_price": sum(offer.price or 0 for offer in offers) / len(offers) if offers else 0, "average_price": sum(offer.price or 0 for offer in offers) / len(offers) if offers else 0,
"revenue_growth": 0.12 "revenue_growth": 0.12
} }

View File

@@ -36,6 +36,6 @@
"author": "AITBC Team", "author": "AITBC Team",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=22.22.0" "node": ">=24.14.0"
} }
} }

View File

@@ -917,18 +917,20 @@ def send(ctx, chain_id, from_addr, to, data, nonce):
config = ctx.obj['config'] config = ctx.obj['config']
try: try:
import httpx import httpx
import json
with httpx.Client() as client: with httpx.Client() as client:
try:
payload_data = json.loads(data)
except json.JSONDecodeError:
payload_data = {"raw_data": data}
tx_payload = { tx_payload = {
"type": "TRANSFER", "type": "TRANSFER",
"chain_id": chain_id, "sender": from_addr,
"from_address": from_addr,
"to_address": to,
"value": 0,
"gas_limit": 100000,
"gas_price": 1,
"nonce": nonce, "nonce": nonce,
"data": data, "fee": 0,
"signature": "mock_signature" "payload": payload_data,
"sig": "mock_signature"
} }
response = client.post( response = client.post(

View File

@@ -9,12 +9,57 @@ from ..core.genesis_generator import GenesisGenerator, GenesisValidationError
from ..core.config import MultiChainConfig, load_multichain_config from ..core.config import MultiChainConfig, load_multichain_config
from ..models.chain import GenesisConfig from ..models.chain import GenesisConfig
from ..utils import output, error, success from ..utils import output, error, success
from .keystore import create_keystore_via_script
import subprocess
import sys
@click.group() @click.group()
def genesis(): def genesis():
"""Genesis block generation and management commands""" """Genesis block generation and management commands"""
pass 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() @genesis.command()
@click.argument('config_file', type=click.Path(exists=True)) @click.argument('config_file', type=click.Path(exists=True))
@click.option('--output', '-o', 'output_file', help='Output file path') @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

@@ -290,8 +290,11 @@ class DualModeWalletAdapter:
def _send_transaction_file(self, wallet_name: str, password: str, to_address: str, def _send_transaction_file(self, wallet_name: str, password: str, to_address: str,
amount: float, description: Optional[str]) -> Dict[str, Any]: amount: float, description: Optional[str]) -> Dict[str, Any]:
"""Send transaction using file-based storage""" """Send transaction using file-based storage and blockchain RPC"""
from .commands.wallet import _load_wallet, _save_wallet from .commands.wallet import _load_wallet, _save_wallet
import httpx
from .utils import error, success
from datetime import datetime
wallet_path = self.wallet_dir / f"{wallet_name}.json" wallet_path = self.wallet_dir / f"{wallet_name}.json"
@@ -300,23 +303,66 @@ class DualModeWalletAdapter:
raise Exception("Wallet not found") raise Exception("Wallet not found")
wallet_data = _load_wallet(wallet_path, wallet_name) wallet_data = _load_wallet(wallet_path, wallet_name)
balance = wallet_data.get("balance", 0) # Fetch current balance and nonce from blockchain
from_address = wallet_data.get("address")
if balance < amount: if not from_address:
error(f"Insufficient balance. Available: {balance}, Required: {amount}") error("Wallet does not have an address configured")
raise Exception("Invalid wallet")
rpc_url = self.config.blockchain_rpc_url
try:
resp = httpx.get(f"{rpc_url}/rpc/getBalance/{from_address}?chain_id=ait-mainnet", timeout=5)
if resp.status_code == 200:
data = resp.json()
chain_balance = data.get("balance", 0)
nonce = data.get("nonce", 0)
else:
error(f"Failed to get balance from chain: {resp.text}")
raise Exception("Chain error")
except Exception as e:
error(f"Failed to connect to blockchain RPC: {e}")
raise
if chain_balance < amount:
error(f"Insufficient blockchain balance. Available: {chain_balance}, Required: {amount}")
raise Exception("Insufficient balance") raise Exception("Insufficient balance")
# Construct and send transaction
tx_payload = {
"type": "TRANSFER",
"sender": from_address,
"nonce": nonce,
"fee": 0,
"payload": {"to": to_address, "value": amount},
"sig": "mock_signature" # Replace with real signature when implemented
}
# Add transaction try:
resp = httpx.post(f"{rpc_url}/rpc/sendTx", json=tx_payload, timeout=5)
if resp.status_code not in (200, 201):
error(f"Failed to submit transaction to chain: {resp.text}")
raise Exception("Chain submission failed")
tx_hash = resp.json().get("tx_hash")
except Exception as e:
error(f"Failed to send transaction to RPC: {e}")
raise
# Add transaction to local history
transaction = { transaction = {
"type": "send", "type": "send",
"amount": -amount, "amount": -amount,
"to_address": to_address, "to_address": to_address,
"description": description or "", "description": description or "",
"timestamp": datetime.now().isoformat(), "timestamp": datetime.now().isoformat(),
"tx_hash": tx_hash,
"status": "pending"
} }
if "transactions" not in wallet_data:
wallet_data["transactions"] = []
wallet_data["transactions"].append(transaction) wallet_data["transactions"].append(transaction)
wallet_data["balance"] = balance - amount wallet_data["balance"] = chain_balance - amount
# Save wallet - CRITICAL SECURITY FIX: Always use password if wallet is encrypted # Save wallet - CRITICAL SECURITY FIX: Always use password if wallet is encrypted
save_password = password if wallet_data.get("encrypted") else None save_password = password if wallet_data.get("encrypted") else None
@@ -325,14 +371,14 @@ class DualModeWalletAdapter:
raise Exception("Password required for encrypted wallet") raise Exception("Password required for encrypted wallet")
_save_wallet(wallet_path, wallet_data, save_password) _save_wallet(wallet_path, wallet_data, save_password)
success(f"Sent {amount} AITBC to {to_address}") success(f"Submitted transaction {tx_hash} to send {amount} AITBC to {to_address}")
return { return {
"mode": "file", "mode": "file",
"wallet_name": wallet_name, "wallet_name": wallet_name,
"to_address": to_address, "to_address": to_address,
"amount": amount, "amount": amount,
"description": description, "description": description,
"new_balance": wallet_data["balance"], "tx_hash": tx_hash,
"timestamp": transaction["timestamp"] "timestamp": transaction["timestamp"]
} }

View File

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

View File

@@ -365,3 +365,4 @@ def create_http_client_with_retry(
transport=RetryTransport(), transport=RetryTransport(),
timeout=timeout timeout=timeout
) )
from .subprocess import run_subprocess

View File

@@ -0,0 +1,31 @@
import subprocess
import sys
from typing import List, Optional, Union, Any
from . import error, output
def run_subprocess(cmd: List[str], check: bool = True, capture_output: bool = True, shell: bool = False, **kwargs: Any) -> Optional[Union[str, subprocess.CompletedProcess]]:
"""Run a subprocess command safely with logging"""
try:
if shell:
# When shell=True, cmd should be a string
cmd_str = " ".join(cmd) if isinstance(cmd, list) else cmd
result = subprocess.run(cmd_str, shell=True, check=check, capture_output=capture_output, text=True, **kwargs)
else:
result = subprocess.run(cmd, check=check, capture_output=capture_output, text=True, **kwargs)
if capture_output:
return result.stdout.strip()
return result
except subprocess.CalledProcessError as e:
error(f"Command failed with exit code {e.returncode}")
if capture_output and getattr(e, 'stderr', None):
print(e.stderr, file=sys.stderr)
if check:
sys.exit(e.returncode)
return getattr(e, 'stdout', None) if capture_output else None
except Exception as e:
error(f"Failed to execute command: {e}")
if check:
sys.exit(1)
return None

View File

@@ -1 +1 @@
22.22.0 24.14.0

6
dev/scripts/dev_heartbeat.py Normal file → Executable file
View File

@@ -38,10 +38,10 @@ def check_build_tests():
rc, out = sh("poetry check") rc, out = sh("poetry check")
checks.append(("poetry check", rc == 0, out)) checks.append(("poetry check", rc == 0, out))
# 2) Fast syntax check of CLI package # 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")) checks.append(("cli syntax", rc == 0, out if rc != 0 else "OK"))
# 3) Minimal test run (dry-run or 1 quick test) # 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 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")) 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) all_ok = all(ok for _, ok, _ in checks)
@@ -86,7 +86,7 @@ def check_vulnerabilities():
"""Run security audits for Python and Node dependencies.""" """Run security audits for Python and Node dependencies."""
issues = [] issues = []
# Python: pip-audit (if available) # 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: if rc == 0:
# No vulnerabilities # No vulnerabilities
pass pass

View File

@@ -20,7 +20,7 @@ Internet → aitbc.bubuit.net (HTTPS :443)
│ │ Container: aitbc (10.1.223.1) │ │ │ │ Container: aitbc (10.1.223.1) │ │
│ │ Access: ssh aitbc-cascade │ │ │ │ Access: ssh aitbc-cascade │ │
│ │ OS: Debian 13 Trixie │ │ │ │ OS: Debian 13 Trixie │ │
│ │ Node.js: 22+ │ │ │ │ Node.js: 24+ │ │
│ │ Python: 3.13.5+ │ │ │ │ Python: 3.13.5+ │ │
│ │ GPU Access: None (CPU-only mode) │ │ │ │ GPU Access: None (CPU-only mode) │ │
│ │ Miner Service: Not needed │ │ │ │ Miner Service: Not needed │ │
@@ -103,7 +103,7 @@ Internet → aitbc.bubuit.net (HTTPS :443)
- **Hostname**: `at1` (primary development workstation) - **Hostname**: `at1` (primary development workstation)
- **Environment**: Windsurf development environment - **Environment**: Windsurf development environment
- **OS**: Debian 13 Trixie (development environment) - **OS**: Debian 13 Trixie (development environment)
- **Node.js**: 22+ (current tested: v22.22.x) - **Node.js**: 24+ (current tested: v24.14.x)
- **Python**: 3.13.5+ (minimum requirement, strictly enforced) - **Python**: 3.13.5+ (minimum requirement, strictly enforced)
- **GPU Access**: **Primary GPU access location** - all GPU workloads must run on at1 - **GPU Access**: **Primary GPU access location** - all GPU workloads must run on at1
- **Architecture**: x86_64 Linux with CUDA GPU support - **Architecture**: x86_64 Linux with CUDA GPU support
@@ -136,7 +136,7 @@ aitbc-mock-coordinator.service # Mock coordinator on port 8020
**Service Details:** **Service Details:**
- **Working Directory**: `/opt/aitbc/` (standard path for all services) - **Working Directory**: `/opt/aitbc/` (standard path for all services)
- **Python Environment**: `/opt/aitbc/.venv/bin/python` (Python 3.13.5+) - **Python Environment**: `/opt/aitbc/.venv/bin/python` (Python 3.13.5+)
- **Node.js Environment**: System Node.js 22+ (current tested: v22.22.x) - **Node.js Environment**: System Node.js 24+ (current tested: v24.14.x)
- **User**: oib - **User**: oib
- **Restart Policy**: always (with 5s delay) - **Restart Policy**: always (with 5s delay)
@@ -204,7 +204,7 @@ ls -la /opt/aitbc/systemd # Should show symlink to windsurf system
└── systemd -> /home/oib/windsurf/aitbc/systemd/ └── systemd -> /home/oib/windsurf/aitbc/systemd/
# Node.js environment # Node.js environment
node --version # Should show v22.22.x node --version # Should show v24.14.x
npm --version # Should show compatible version npm --version # Should show compatible version
``` ```
@@ -217,7 +217,7 @@ ls -la /opt/aitbc/ # Should show individual symlinks, not s
ls -la /opt/aitbc/apps/blockchain-node # Should point to windsurf project ls -la /opt/aitbc/apps/blockchain-node # Should point to windsurf project
python3 --version # Should show Python 3.13.5 python3 --version # Should show Python 3.13.5
ls -la /home/oib/windsurf/aitbc/.venv/bin/python # Check development venv ls -la /home/oib/windsurf/aitbc/.venv/bin/python # Check development venv
node --version # Should show v22.22.x node --version # Should show v24.14.x
npm --version # Should show compatible version npm --version # Should show compatible version
# Test symlink resolution # Test symlink resolution
@@ -307,7 +307,7 @@ ssh aitbc1-cascade # Direct SSH to aitbc1 container (incus)
- Purpose: secondary AITBC dev environment (incus container) - Purpose: secondary AITBC dev environment (incus container)
- Host: 10.1.223.40 (Debian 13 Trixie), accessible via new SSH alias `aitbc1-cascade` - Host: 10.1.223.40 (Debian 13 Trixie), accessible via new SSH alias `aitbc1-cascade`
- OS: Debian 13 Trixie (development environment) - OS: Debian 13 Trixie (development environment)
- Node.js: 22+ (current tested: v22.22.x) - Node.js: 24+ (current tested: v24.14.x)
- Python: 3.13.5+ (minimum requirement, strictly enforced) - Python: 3.13.5+ (minimum requirement, strictly enforced)
- Proxy device: incus proxy on host maps 127.0.0.1:18001 → 127.0.0.1:8000 inside container - Proxy device: incus proxy on host maps 127.0.0.1:18001 → 127.0.0.1:8000 inside container
- AppArmor profile: unconfined (incus raw.lxc) - AppArmor profile: unconfined (incus raw.lxc)
@@ -353,9 +353,9 @@ ssh aitbc1-cascade # Direct SSH to aitbc1 container (incus)
| Web UI | 8016 | python | 3.13.5 | /app/ | ✅ | | Web UI | 8016 | python | 3.13.5 | /app/ | ✅ |
| Geographic Load Balancer | 8017 | python | 3.13.5 | /api/loadbalancer/* | ✅ | | Geographic Load Balancer | 8017 | python | 3.13.5 | /api/loadbalancer/* | ✅ |
**Python 3.13.5 and Node.js 22+ Upgrade Complete** (2026-03-05): **Python 3.13.5 and Node.js 24+ Upgrade Complete** (2026-03-05):
- All services upgraded to Python 3.13.5 - All services upgraded to Python 3.13.5
- Node.js upgraded to 22+ (current tested: v22.22.x) - Node.js upgraded to 24+ (current tested: v24.14.x)
- Virtual environments updated and verified - Virtual environments updated and verified
- API routing fixed for external access - API routing fixed for external access
- Services fully operational with enhanced performance - Services fully operational with enhanced performance
@@ -381,7 +381,7 @@ All Python services in the AITBC container run on **Python 3.13.5** with isolate
**Verification Commands:** **Verification Commands:**
```bash ```bash
ssh aitbc-cascade "python3 --version" # Should show Python 3.13.5 ssh aitbc-cascade "python3 --version" # Should show Python 3.13.5
ssh aitbc-cascade "node --version" # Should show v22.22.x ssh aitbc-cascade "node --version" # Should show v24.14.x
ssh aitbc-cascade "npm --version" # Should show compatible version ssh aitbc-cascade "npm --version" # Should show compatible version
ssh aitbc-cascade "ls -la /opt/*/.venv/bin/python" # Check venv symlinks ssh aitbc-cascade "ls -la /opt/*/.venv/bin/python" # Check venv symlinks
ssh aitbc-cascade "curl -s http://127.0.0.1:8000/v1/health" # Coordinator API health ssh aitbc-cascade "curl -s http://127.0.0.1:8000/v1/health" # Coordinator API health

View File

@@ -25,7 +25,7 @@ This guide provides comprehensive deployment instructions for the **aitbc server
### **Software Requirements** ### **Software Requirements**
- **Operating System**: Debian 13 Trixie (primary) or Ubuntu 22.04+ (alternative) - **Operating System**: Debian 13 Trixie (primary) or Ubuntu 22.04+ (alternative)
- **Python**: 3.13.5+ (strictly enforced - platform requires 3.13+ features) - **Python**: 3.13.5+ (strictly enforced - platform requires 3.13+ features)
- **Node.js**: 22+ (current tested: v22.22.x) - **Node.js**: 24+ (current tested: v24.14.x)
- **Database**: SQLite (default) or PostgreSQL (production) - **Database**: SQLite (default) or PostgreSQL (production)
### **Network Requirements** ### **Network Requirements**

View File

@@ -176,9 +176,9 @@ python3 --version # Should show 3.13.x
### **🔥 Issue 1b: Node.js Version Compatibility** ### **🔥 Issue 1b: Node.js Version Compatibility**
**Current Status**: Node.js v22.22.x (tested and compatible) **Current Status**: Node.js v24.14.x (tested and compatible)
**Note**: Current Node.js version v22.22.x meets the minimum requirement of 22.0.0 and is fully compatible with AITBC platform. **Note**: Current Node.js version v24.14.x meets the minimum requirement of 24.14.0 and is fully compatible with AITBC platform.
### **🔥 Issue 1c: Operating System Compatibility** ### **🔥 Issue 1c: Operating System Compatibility**

32
drain_test.py Normal file
View File

@@ -0,0 +1,32 @@
import sys
from pathlib import Path
import json
# Setup sys.path
sys.path.insert(0, str(Path('/opt/aitbc/apps/blockchain-node/src')))
from aitbc_chain.config import settings
from aitbc_chain.mempool import init_mempool, get_mempool
# Use development mempool backend configuration exactly like main node
init_mempool(
backend=settings.mempool_backend,
db_path=str(settings.db_path.parent / "mempool.db"),
max_size=settings.mempool_max_size,
min_fee=settings.min_fee,
)
mempool = get_mempool()
print(f"Mempool class: {mempool.__class__.__name__}")
print(f"Mempool DB path: {mempool._db_path}")
chain_id = 'ait-mainnet'
rows = mempool._conn.execute("SELECT * FROM mempool WHERE chain_id = ?", (chain_id,)).fetchall()
print(f"Found {len(rows)} raw rows in DB")
for r in rows:
print(r)
txs = mempool.drain(100, 1000000, chain_id)
print(f"Drained {len(txs)} txs")
for tx in txs:
print(tx)

9
fix_gossip.patch Normal file
View File

@@ -0,0 +1,9 @@
--- /opt/aitbc/apps/blockchain-node/src/aitbc_chain/gossip/broker.py 2026-03-23 12:40:00.000000000 +0100
+++ /opt/aitbc/apps/blockchain-node/src/aitbc_chain/gossip/broker.py.new 2026-03-23 12:40:00.000000000 +0100
@@ -6,7 +6,7 @@
import warnings
from collections import defaultdict
-from contextlib import suppress
+from contextlib import suppress, asynccontextmanager
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Set

30
fix_inprocess.py Normal file
View File

@@ -0,0 +1,30 @@
import asyncio
from contextlib import asynccontextmanager
from typing import Any
class _InProcessSubscriber:
def __init__(self, queue, release):
self._queue = queue
self._release = release
def __aiter__(self):
return self._iterator()
async def _iterator(self):
try:
while True:
yield await self._queue.get()
finally:
pass
@asynccontextmanager
async def subscribe():
queue = asyncio.Queue()
try:
yield _InProcessSubscriber(queue, lambda: None)
finally:
pass
async def main():
async with subscribe() as sub:
print("Success")
asyncio.run(main())

10
fix_poa.py Normal file
View File

@@ -0,0 +1,10 @@
import re
with open("/opt/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py", "r") as f:
content = f.read()
# Make sure we use the correct chain_id when draining from mempool
new_content = content.replace("mempool.drain(max_txs, max_bytes, self._config.chain_id)", "mempool.drain(max_txs, max_bytes, 'ait-mainnet')")
with open("/opt/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py", "w") as f:
f.write(new_content)

10
fix_router.py Normal file
View File

@@ -0,0 +1,10 @@
import re
with open("/opt/aitbc/apps/blockchain-node/src/aitbc_chain/rpc/router.py", "r") as f:
content = f.read()
# Make sure we use the correct chain_id when adding to mempool
new_content = content.replace("mempool.add(tx_dict, chain_id=chain_id)", "mempool.add(tx_dict, chain_id=chain_id or request.payload.get('chain_id') or 'ait-mainnet')")
with open("/opt/aitbc/apps/blockchain-node/src/aitbc_chain/rpc/router.py", "w") as f:
f.write(new_content)

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

@@ -60,7 +60,7 @@
}, },
"homepage": "https://aitbc.bubuit.net/docs/", "homepage": "https://aitbc.bubuit.net/docs/",
"engines": { "engines": {
"node": ">=22.22.0" "node": ">=24.14.0"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

View File

@@ -25,6 +25,6 @@
"@openzeppelin/contracts": "^5.0.2" "@openzeppelin/contracts": "^5.0.2"
}, },
"engines": { "engines": {
"node": ">=22.22.0" "node": ">=24.14.0"
} }
} }

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;
}
}

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