Compare commits
19 Commits
92f3d84815
...
b4b5a57390
| Author | SHA1 | Date | |
|---|---|---|---|
| b4b5a57390 | |||
| 5f2ab48b9a | |||
| 1205a7c681 | |||
| 97d989bc04 | |||
| ffbf0b8966 | |||
| 4c3db7c019 | |||
| 594c3c6b0f | |||
|
|
690dcd2407 | ||
|
|
8a312cc498 | ||
| 7e4154a568 | |||
| 8327f6e2b6 | |||
| 37e5e2d5cd | |||
|
|
c2fa6737dc | ||
|
|
3df15a0d8d | ||
| feb4281efd | |||
| e327a8f487 | |||
| 337c68013c | |||
| f11f277e71 | |||
| 258b320d3a |
2
.aitbc.yaml
Normal file
2
.aitbc.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
api_key: test_value
|
||||
coordinator_url: http://127.0.0.1:18000
|
||||
391
.gitignore
vendored
391
.gitignore
vendored
@@ -1,7 +1,4 @@
|
||||
<<<<<<< Updated upstream
|
||||
# AITBC Monorepo ignore rules
|
||||
# Updated: 2026-03-03 - Project organization workflow completed
|
||||
# Development files organized into dev/ subdirectories
|
||||
|
||||
# ===================
|
||||
# Python
|
||||
@@ -26,7 +23,9 @@ htmlcov/
|
||||
.mypy_cache/
|
||||
.ruff_cache/
|
||||
|
||||
# Environment files
|
||||
# ===================
|
||||
# Environment Files (SECRETS - NEVER COMMIT)
|
||||
# ===================
|
||||
*.env
|
||||
.env.*
|
||||
!.env.example
|
||||
@@ -34,90 +33,45 @@ htmlcov/
|
||||
.env.*.local
|
||||
|
||||
# ===================
|
||||
# Development Environment (organized)
|
||||
# ===================
|
||||
dev/env/.venv/
|
||||
dev/env/node_modules/
|
||||
dev/env/cli_env/
|
||||
dev/cache/.pytest_cache/
|
||||
dev/cache/.ruff_cache/
|
||||
dev/cache/.vscode/
|
||||
dev/cache/logs/
|
||||
dev/scripts/__pycache__/
|
||||
dev/scripts/*.pyc
|
||||
dev/scripts/*.pyo
|
||||
|
||||
# ===================
|
||||
# Databases
|
||||
# Database & Data
|
||||
# ===================
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
*/data/*.db
|
||||
*.db-wal
|
||||
*.db-shm
|
||||
data/
|
||||
|
||||
# Alembic
|
||||
alembic.ini
|
||||
migrations/versions/__pycache__/
|
||||
apps/blockchain-node/data/
|
||||
|
||||
# ===================
|
||||
# Node / JavaScript
|
||||
# Logs & Runtime
|
||||
# ===================
|
||||
node_modules/
|
||||
dist/
|
||||
build/
|
||||
.npm/
|
||||
.pnpm/
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
.next/
|
||||
.nuxt/
|
||||
.cache/
|
||||
|
||||
# ===================
|
||||
# Development Tests (organized)
|
||||
# ===================
|
||||
dev/tests/__pycache__/
|
||||
dev/tests/*.pyc
|
||||
dev/tests/test_results/
|
||||
dev/tests/simple_test_results.json
|
||||
dev/tests/data/
|
||||
dev/tests/*.db
|
||||
dev/multi-chain/__pycache__/
|
||||
dev/multi-chain/*.pyc
|
||||
dev/multi-chain/test_results/
|
||||
|
||||
# ===================
|
||||
# Logs & Runtime (organized)
|
||||
# ===================
|
||||
logs/
|
||||
dev/cache/logs/
|
||||
*.log
|
||||
*.log.*
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pids/
|
||||
logs/
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# ===================
|
||||
# Editor & IDE
|
||||
# Secrets & Credentials
|
||||
# ===================
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
*.p12
|
||||
secrets/
|
||||
credentials/
|
||||
.secrets
|
||||
.gitea_token.sh
|
||||
keystore/
|
||||
|
||||
# ===================
|
||||
# IDE & Editor
|
||||
# ===================
|
||||
.idea/
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.project
|
||||
.classpath
|
||||
.settings/
|
||||
|
||||
# ===================
|
||||
# Runtime / PID files
|
||||
# ===================
|
||||
*.pid
|
||||
apps/.service_pids
|
||||
|
||||
# ===================
|
||||
# OS Files
|
||||
@@ -132,133 +86,22 @@ Desktop.ini
|
||||
# ===================
|
||||
# Build & Compiled
|
||||
# ===================
|
||||
build/
|
||||
dist/
|
||||
target/
|
||||
*.o
|
||||
*.a
|
||||
*.lib
|
||||
*.dll
|
||||
*.dylib
|
||||
target/
|
||||
out/
|
||||
|
||||
# ===================
|
||||
# Secrets & Credentials
|
||||
# Node.js
|
||||
# ===================
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
*.p12
|
||||
secrets/
|
||||
credentials/
|
||||
.secrets
|
||||
.gitea_token.sh
|
||||
|
||||
# ===================
|
||||
# Backup Files (organized)
|
||||
# ===================
|
||||
backup/**/*.tmp
|
||||
backup/**/*.temp
|
||||
backup/**/.DS_Store
|
||||
backup/updates/*.log
|
||||
|
||||
# Large backup files (exceed GitHub size limits)
|
||||
backup/updates/*.tar.gz
|
||||
backup/updates/*.zip
|
||||
backup/updates/*.tar.bz2
|
||||
|
||||
# Application backup archives
|
||||
backup/explorer_backup_*.tar.gz
|
||||
backup/*_backup_*.tar.gz
|
||||
backup/*_backup_*.zip
|
||||
|
||||
# Backup documentation and indexes
|
||||
backup/BACKUP_INDEX.md
|
||||
backup/*.md
|
||||
backup/README.md
|
||||
|
||||
# ===================
|
||||
# Temporary Files
|
||||
# ===================
|
||||
tmp/
|
||||
temp/
|
||||
=======
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# Virtual environments
|
||||
venv/
|
||||
env/
|
||||
ENV/
|
||||
.venv/
|
||||
.env/
|
||||
|
||||
# IDEs
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Database
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
*.db-wal
|
||||
*.db-shm
|
||||
|
||||
# Configuration with secrets
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
config.json
|
||||
secrets.json
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
*.bak
|
||||
*.backup
|
||||
|
||||
# ===================
|
||||
# Environment Files
|
||||
# ===================
|
||||
.env
|
||||
.env.local
|
||||
.env.production
|
||||
*.env
|
||||
.env.*.local
|
||||
node_modules/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# ===================
|
||||
# Windsurf IDE
|
||||
@@ -267,164 +110,26 @@ secrets.json
|
||||
.snapshots/
|
||||
|
||||
# ===================
|
||||
# Test Results & Artifacts
|
||||
# Wallet Files (contain private keys)
|
||||
# ===================
|
||||
*.json
|
||||
home/client/client_wallet.json
|
||||
home/genesis_wallet.json
|
||||
home/miner/miner_wallet.json
|
||||
|
||||
# ===================
|
||||
# Test Results
|
||||
# ===================
|
||||
test-results/
|
||||
**/test-results/
|
||||
|
||||
# ===================
|
||||
# Development Logs - Keep in dev/logs/
|
||||
# Temporary Files
|
||||
# ===================
|
||||
*.log
|
||||
*.out
|
||||
*.err
|
||||
wget-log
|
||||
download.log
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
*.temp
|
||||
*.bak
|
||||
*.backup
|
||||
|
||||
# ===================
|
||||
# Wallet files (contain keys/balances)
|
||||
# ===================
|
||||
home/client/client_wallet.json
|
||||
home/genesis_wallet.json
|
||||
home/miner/miner_wallet.json
|
||||
|
||||
# Root-level wallet backups (contain private keys)
|
||||
*.json
|
||||
|
||||
# ===================
|
||||
# Stale source copies
|
||||
# ===================
|
||||
src/aitbc_chain/
|
||||
|
||||
# ===================
|
||||
# Project Specific
|
||||
# ===================
|
||||
# Coordinator database
|
||||
apps/coordinator-api/src/*.db
|
||||
|
||||
# Blockchain node data
|
||||
apps/blockchain-node/data/
|
||||
|
||||
# Explorer build artifacts
|
||||
apps/explorer-web/dist/
|
||||
|
||||
# Solidity build artifacts
|
||||
packages/solidity/aitbc-token/typechain-types/
|
||||
packages/solidity/aitbc-token/artifacts/
|
||||
packages/solidity/aitbc-token/cache/
|
||||
|
||||
# Local test fixtures and E2E testing
|
||||
tests/e2e/fixtures/home/**/.aitbc/cache/
|
||||
tests/e2e/fixtures/home/**/.aitbc/logs/
|
||||
tests/e2e/fixtures/home/**/.aitbc/tmp/
|
||||
tests/e2e/fixtures/home/**/.aitbc/*.log
|
||||
tests/e2e/fixtures/home/**/.aitbc/*.pid
|
||||
tests/e2e/fixtures/home/**/.aitbc/*.sock
|
||||
|
||||
# Keep fixture structure but exclude generated content
|
||||
!tests/e2e/fixtures/home/
|
||||
!tests/e2e/fixtures/home/**/
|
||||
!tests/e2e/fixtures/home/**/.aitbc/
|
||||
!tests/e2e/fixtures/home/**/.aitbc/wallets/
|
||||
!tests/e2e/fixtures/home/**/.aitbc/config/
|
||||
|
||||
# Local test data
|
||||
tests/fixtures/generated/
|
||||
|
||||
# GPU miner local configs
|
||||
scripts/gpu/*.local.py
|
||||
|
||||
# Deployment secrets
|
||||
scripts/deploy/*.secret.*
|
||||
infra/nginx/*.local.conf
|
||||
|
||||
# ===================
|
||||
# Documentation
|
||||
# ===================
|
||||
# Infrastructure docs (contains sensitive network info)
|
||||
docs/infrastructure.md
|
||||
# Workflow files (personal, change frequently)
|
||||
docs/1_project/3_currenttask.md
|
||||
docs/1_project/4_currentissue.md
|
||||
|
||||
# ===================
|
||||
# Website (local deployment details)
|
||||
# ===================
|
||||
website/README.md
|
||||
website/aitbc-proxy.conf
|
||||
|
||||
# ===================
|
||||
# Local Config & Secrets
|
||||
# ===================
|
||||
.aitbc.yaml
|
||||
apps/coordinator-api/.env
|
||||
|
||||
# ===================
|
||||
# Windsurf IDE (personal dev tooling)
|
||||
# ===================
|
||||
.windsurf/
|
||||
|
||||
# ===================
|
||||
# Deploy Scripts (hardcoded local paths & IPs)
|
||||
# ===================
|
||||
scripts/deploy/*
|
||||
!scripts/deploy/*.example
|
||||
scripts/gpu/*
|
||||
!scripts/gpu/*.example
|
||||
scripts/service/*
|
||||
|
||||
# ===================
|
||||
# Infra Configs (production IPs & secrets)
|
||||
# ===================
|
||||
infra/nginx/nginx-aitbc*.conf
|
||||
infra/helm/values/prod/
|
||||
infra/helm/values/prod.yaml
|
||||
=======
|
||||
# Node.js
|
||||
node_modules/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Build artifacts
|
||||
build/
|
||||
dist/
|
||||
target/
|
||||
|
||||
# System files
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Coverage reports
|
||||
htmlcov/
|
||||
.coverage
|
||||
.coverage.*
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# Environments
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# AITBC specific
|
||||
data/
|
||||
logs/
|
||||
*.db
|
||||
*.sqlite
|
||||
wallet*.json
|
||||
keystore/
|
||||
certificates/
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
29
README.md
29
README.md
@@ -89,28 +89,30 @@ aitbc marketplace list --translate-to french
|
||||
|
||||
## 🔗 Blockchain Node (Brother Chain)
|
||||
|
||||
A minimal asset-backed blockchain that validates compute receipts and mints AIT tokens.
|
||||
Production-ready blockchain with fixed supply and secure key management.
|
||||
|
||||
### ✅ Current Status
|
||||
- **Chain ID**: `ait-devnet`
|
||||
- **Chain ID**: `ait-mainnet` (production)
|
||||
- **Consensus**: Proof-of-Authority (single proposer)
|
||||
- **RPC Endpoint**: `http://localhost:8026/rpc`
|
||||
- **Health Check**: `http://localhost:8026/health`
|
||||
- **Metrics**: `http://localhost:8026/metrics` (Prometheus format)
|
||||
- **Status**: 🟢 Operational and fully functional
|
||||
- **RPC Endpoint**: `http://127.0.0.1:8026/rpc`
|
||||
- **Health Check**: `http://127.0.0.1:8026/health`
|
||||
- **Metrics**: `http://127.0.0.1:8026/metrics` (Prometheus format)
|
||||
- **Status**: 🟢 Operational with immutable supply, no admin minting
|
||||
|
||||
### 🚀 Quick Launch
|
||||
### 🚀 Quick Launch (First Time)
|
||||
|
||||
```bash
|
||||
# 1. Generate keystore and genesis
|
||||
cd /opt/aitbc/apps/blockchain-node
|
||||
source .venv/bin/activate
|
||||
bash scripts/devnet_up.sh
|
||||
.venv/bin/python scripts/setup_production.py --chain-id ait-mainnet
|
||||
|
||||
# 2. Start the node (production)
|
||||
bash scripts/mainnet_up.sh
|
||||
```
|
||||
|
||||
The node starts:
|
||||
- Proposer loop (block production)
|
||||
- RPC API on port 8026
|
||||
- Mock coordinator on port 8090 (for testing)
|
||||
- RPC API on `http://127.0.0.1:8026`
|
||||
|
||||
### 🛠️ CLI Interaction
|
||||
|
||||
@@ -123,11 +125,10 @@ aitbc blockchain head
|
||||
|
||||
# Check balance
|
||||
aitbc blockchain balance --address <your-address>
|
||||
|
||||
# Fund an address (devnet faucet)
|
||||
aitbc blockchain faucet --address <your-address> --amount 1000
|
||||
```
|
||||
|
||||
> **Note**: The devnet faucet (`aitbc blockchain faucet`) has been removed. All tokens are allocated at genesis to the `aitbc1genesis` wallet.
|
||||
|
||||
For full documentation, see: [`apps/blockchain-node/README.md`](./apps/blockchain-node/README.md)
|
||||
|
||||
## 🤖 Agent-First Computing
|
||||
|
||||
@@ -1,129 +1,165 @@
|
||||
# Blockchain Node (Brother Chain)
|
||||
|
||||
Minimal asset-backed blockchain node that validates compute receipts and mints AIT tokens.
|
||||
Production-ready blockchain node for AITBC with fixed supply and secure key management.
|
||||
|
||||
## Status
|
||||
|
||||
✅ **Operational** — Core blockchain functionality implemented and running.
|
||||
✅ **Operational** — Core blockchain functionality implemented.
|
||||
|
||||
### Capabilities
|
||||
- PoA consensus with single proposer (devnet)
|
||||
- PoA consensus with single proposer
|
||||
- Transaction processing (TRANSFER, RECEIPT_CLAIM)
|
||||
- Receipt validation and minting
|
||||
- Gossip-based peer-to-peer networking (in-memory backend)
|
||||
- RESTful RPC API (`/rpc/*`)
|
||||
- Prometheus metrics (`/metrics`)
|
||||
- Health check endpoint (`/health`)
|
||||
- SQLite persistence with Alembic migrations
|
||||
- Multi-chain support (separate data directories per chain ID)
|
||||
|
||||
## Quickstart (Devnet)
|
||||
## Architecture
|
||||
|
||||
The blockchain node is already set up with a virtualenv. To launch:
|
||||
### Wallets & Supply
|
||||
- **Fixed supply**: All tokens minted at genesis; no further minting.
|
||||
- **Two wallets**:
|
||||
- `aitbc1genesis` (treasury): holds the full initial supply (default 1 B AIT). This is the **cold storage** wallet; private key is encrypted in keystore.
|
||||
- `aitbc1treasury` (spending): operational wallet for transactions; initially zero balance. Can receive funds from genesis wallet.
|
||||
- **Private keys** are stored in `keystore/*.json` using AES‑256‑GCM encryption. Password is stored in `keystore/.password` (mode 600).
|
||||
|
||||
### Chain Configuration
|
||||
- **Chain ID**: `ait-mainnet` (production)
|
||||
- **Proposer**: The genesis wallet address is the block proposer and authority.
|
||||
- **Trusted proposers**: Only the genesis wallet is allowed to produce blocks.
|
||||
- **No admin endpoints**: The `/rpc/admin/mintFaucet` endpoint has been removed.
|
||||
|
||||
## Quickstart (Production)
|
||||
|
||||
### 1. Generate Production Keys & Genesis
|
||||
|
||||
Run the setup script once to create the keystore, allocations, and genesis:
|
||||
|
||||
```bash
|
||||
cd /opt/aitbc/apps/blockchain-node
|
||||
source .venv/bin/activate
|
||||
bash scripts/devnet_up.sh
|
||||
.venv/bin/python scripts/setup_production.py --chain-id ait-mainnet
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Generate genesis block at `data/devnet/genesis.json`
|
||||
2. Start the blockchain node proposer loop (PID logged)
|
||||
3. Start RPC API on `http://127.0.0.1:8026`
|
||||
4. Start mock coordinator on `http://127.0.0.1:8090`
|
||||
This creates:
|
||||
- `keystore/aitbc1genesis.json` (treasury wallet)
|
||||
- `keystore/aitbc1treasury.json` (spending wallet)
|
||||
- `keystore/.password` (random strong password)
|
||||
- `data/ait-mainnet/allocations.json`
|
||||
- `data/ait-mainnet/genesis.json`
|
||||
|
||||
Press `Ctrl+C` to stop all processes.
|
||||
**Important**: Back up the keystore directory and the `.password` file securely. Loss of these means loss of funds.
|
||||
|
||||
### Manual Startup
|
||||
### 2. Configure Environment
|
||||
|
||||
If you prefer to start components separately:
|
||||
Copy the provided production environment file:
|
||||
|
||||
```bash
|
||||
# Terminal 1: Blockchain node
|
||||
cd /opt/aitbc/apps/blockchain-node
|
||||
source .venv/bin/activate
|
||||
PYTHONPATH=src python -m aitbc_chain.main
|
||||
cp .env.production .env
|
||||
```
|
||||
|
||||
# Terminal 2: RPC API
|
||||
cd /opt/aitbc/apps/blockchain-node
|
||||
source .venv/bin/activate
|
||||
PYTHONPATH=src uvicorn aitbc_chain.app:app --host 127.0.0.1 --port 8026
|
||||
Edit `.env` if you need to adjust ports or paths. Ensure `chain_id=ait-mainnet` and `proposer_id` matches the genesis wallet address (the setup script sets it automatically in `.env.production`).
|
||||
|
||||
# Terminal 3: Mock coordinator (optional, for testing)
|
||||
### 3. Start the Node
|
||||
|
||||
Use the production launcher:
|
||||
|
||||
```bash
|
||||
bash scripts/mainnet_up.sh
|
||||
```
|
||||
|
||||
This starts:
|
||||
- Blockchain node (PoA proposer)
|
||||
- RPC API on `http://127.0.0.1:8026`
|
||||
|
||||
Press `Ctrl+C` to stop both.
|
||||
|
||||
### Manual Startup (Alternative)
|
||||
|
||||
```bash
|
||||
cd /opt/aitbc/apps/blockchain-node
|
||||
source .venv/bin/activate
|
||||
PYTHONPATH=src uvicorn mock_coordinator:app --host 127.0.0.1 --port 8090
|
||||
source .env.production # or export the variables manually
|
||||
# Terminal 1: Node
|
||||
.venv/bin/python -m aitbc_chain.main
|
||||
# Terminal 2: RPC
|
||||
.venv/bin/bin/uvicorn aitbc_chain.app:app --host 127.0.0.1 --port 8026
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
Once running, the RPC API is available at `http://127.0.0.1:8026/rpc`.
|
||||
RPC API available at `http://127.0.0.1:8026/rpc`.
|
||||
|
||||
### Health & Metrics
|
||||
- `GET /health` — Health check with node info
|
||||
- `GET /metrics` — Prometheus-format metrics
|
||||
|
||||
### Blockchain Queries
|
||||
- `GET /rpc/head` — Current chain head block
|
||||
### Blockchain
|
||||
- `GET /rpc/head` — Current chain head
|
||||
- `GET /rpc/blocks/{height}` — Get block by height
|
||||
- `GET /rpc/blocks-range?start=0&end=10` — Get block range
|
||||
- `GET /rpc/blocks-range?start=0&end=10` — Block range
|
||||
- `GET /rpc/info` — Chain information
|
||||
- `GET /rpc/supply` — Token supply info
|
||||
- `GET /rpc/validators` — List validators
|
||||
- `GET /rpc/supply` — Token supply (total & circulating)
|
||||
- `GET /rpc/validators` — List of authorities
|
||||
- `GET /rpc/state` — Full state dump
|
||||
|
||||
### Transactions
|
||||
- `POST /rpc/sendTx` — Submit transaction (JSON body: `TransactionRequest`)
|
||||
- `POST /rpc/sendTx` — Submit transaction (TRANSFER, RECEIPT_CLAIM)
|
||||
- `GET /rpc/transactions` — Latest transactions
|
||||
- `GET /rpc/tx/{tx_hash}` — Get transaction by hash
|
||||
- `POST /rpc/estimateFee` — Estimate fee for transaction type
|
||||
|
||||
### Receipts (Compute Proofs)
|
||||
- `POST /rpc/submitReceipt` — Submit receipt claim
|
||||
- `GET /rpc/receipts` — Latest receipts
|
||||
- `GET /rpc/receipts/{receipt_id}` — Get receipt by ID
|
||||
- `POST /rpc/estimateFee` — Estimate fee
|
||||
|
||||
### Accounts
|
||||
- `GET /rpc/getBalance/{address}` — Account balance
|
||||
- `GET /rpc/address/{address}` — Address details + txs
|
||||
- `GET /rpc/addresses` — List active addresses
|
||||
|
||||
### Admin
|
||||
- `POST /rpc/admin/mintFaucet` — Mint devnet funds (requires admin key)
|
||||
### Health & Metrics
|
||||
- `GET /health` — Health check
|
||||
- `GET /metrics` — Prometheus metrics
|
||||
|
||||
### Sync
|
||||
- `GET /rpc/syncStatus` — Chain sync status
|
||||
*Note: Admin endpoints (`/rpc/admin/*`) are disabled in production.*
|
||||
|
||||
## CLI Integration
|
||||
## Multi‑Chain Support
|
||||
|
||||
Use the AITBC CLI to interact with the node:
|
||||
The node can run multiple chains simultaneously by setting `supported_chains` in `.env` as a comma‑separated list (e.g., `ait-mainnet,ait-testnet`). Each chain must have its own `data/<chain_id>/genesis.json` and (optionally) its own keystore. The proposer identity is shared across chains; for multi‑chain you may want separate proposer wallets per chain.
|
||||
|
||||
## Keystore Management
|
||||
|
||||
### Encrypted Keystore Format
|
||||
- Uses Web3 keystore format (AES‑256‑GCM + PBKDF2).
|
||||
- Password stored in `keystore/.password` (chmod 600).
|
||||
- Private keys are **never** stored in plaintext.
|
||||
|
||||
### Changing the Password
|
||||
```bash
|
||||
source /opt/aitbc/cli/venv/bin/activate
|
||||
aitbc blockchain status
|
||||
aitbc blockchain head
|
||||
aitbc blockchain balance --address <your-address>
|
||||
aitbc blockchain faucet --address <your-address> --amount 1000
|
||||
# Use the keystore.py script to re‑encrypt with a new password
|
||||
.venv/bin/python scripts/keystore.py --name genesis --show --password <old> --new-password <new>
|
||||
```
|
||||
(Not yet implemented; currently you must manually decrypt and re‑encrypt.)
|
||||
|
||||
## Configuration
|
||||
|
||||
Edit `.env` in this directory to change:
|
||||
|
||||
```
|
||||
CHAIN_ID=ait-devnet
|
||||
DB_PATH=./data/chain.db
|
||||
RPC_BIND_HOST=0.0.0.0
|
||||
RPC_BIND_PORT=8026
|
||||
P2P_BIND_HOST=0.0.0.0
|
||||
P2P_BIND_PORT=7070
|
||||
PROPOSER_KEY=proposer_key_<timestamp>
|
||||
MINT_PER_UNIT=1000
|
||||
COORDINATOR_RATIO=0.05
|
||||
GOSSIP_BACKEND=memory
|
||||
### Adding a New Wallet
|
||||
```bash
|
||||
.venv/bin/python scripts/keystore.py --name mywallet --create
|
||||
```
|
||||
This appends a new entry to `allocations.json` if you want it to receive genesis allocation (edit the file and regenerate genesis).
|
||||
|
||||
Restart the node after changes.
|
||||
## Genesis & Supply
|
||||
|
||||
- Genesis file is generated by `scripts/make_genesis.py`.
|
||||
- Supply is fixed: the sum of `allocations[].balance`.
|
||||
- No tokens can be minted after genesis (`mint_per_unit=0`).
|
||||
- To change the allocation distribution, edit `allocations.json` and regenerate genesis (requires consensus to reset chain).
|
||||
|
||||
## Development / Devnet
|
||||
|
||||
The old devnet (faucet model) has been removed. For local development, use the production setup with a throwaway keystore, or create a separate `ait-devnet` chain by providing your own `allocations.json` and running `scripts/make_genesis.py` manually.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Genesis missing**: Run `scripts/setup_production.py` first.
|
||||
|
||||
**Proposer key not loaded**: Ensure `keystore/aitbc1genesis.json` exists and `keystore/.password` is readable. The node will log a warning but still run (block signing disabled until implemented).
|
||||
|
||||
**Port already in use**: Change `rpc_bind_port` in `.env` and restart.
|
||||
|
||||
**Database locked**: Delete `data/ait-mainnet/chain.db` and restart (only if you're sure no other node is using it).
|
||||
|
||||
## Project Layout
|
||||
|
||||
@@ -138,32 +174,26 @@ blockchain-node/
|
||||
│ ├── gossip/ # P2P message bus
|
||||
│ ├── consensus/ # PoA proposer logic
|
||||
│ ├── rpc/ # RPC endpoints
|
||||
│ ├── contracts/ # Smart contract logic
|
||||
│ └── models.py # SQLModel definitions
|
||||
├── data/
|
||||
│ └── devnet/
|
||||
│ └── genesis.json # Generated by make_genesis.py
|
||||
│ └── ait-mainnet/
|
||||
│ ├── genesis.json # Generated by make_genesis.py
|
||||
│ └── chain.db # SQLite database
|
||||
├── keystore/
|
||||
│ ├── aitbc1genesis.json
|
||||
│ ├── aitbc1treasury.json
|
||||
│ └── .password
|
||||
├── scripts/
|
||||
│ ├── make_genesis.py # Genesis generator
|
||||
│ ├── devnet_up.sh # Devnet launcher
|
||||
│ └── keygen.py # Keypair generator
|
||||
└── .env # Node configuration
|
||||
│ ├── setup_production.py # One‑time production setup
|
||||
│ ├── mainnet_up.sh # Production launcher
|
||||
│ └── keystore.py # Keystore utilities
|
||||
└── .env.production # Production environment template
|
||||
```
|
||||
|
||||
## Notes
|
||||
## Security Notes
|
||||
|
||||
- The node uses proof-of-authority (PoA) consensus with a single proposer for the devnet.
|
||||
- Transactions require a valid signature (ed25519) unless running in test mode.
|
||||
- Receipts represent compute work attestations and mint new AIT tokens to the miner.
|
||||
- Gossip backend defaults to in-memory; for multi-node networks, configure a Redis backend.
|
||||
- RPC API does not require authentication on devnet (add in production).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Port already in use:** Change `RPC_BIND_PORT` in `.env` and restart.
|
||||
|
||||
**Database locked:** Ensure only one node instance is running; delete `data/chain.db` if corrupted.
|
||||
|
||||
**No blocks proposed:** Check proposer logs; ensure `PROPOSER_KEY` is set and no other proposers are conflicting.
|
||||
|
||||
**Mock coordinator not responding:** It's only needed for certain tests; the blockchain node can run standalone.
|
||||
- **Never** expose RPC API to the public internet without authentication (production should add mTLS or API keys).
|
||||
- Keep keystore and password backups offline.
|
||||
- The node runs as the current user; ensure file permissions restrict access to the `keystore/` and `data/` directories.
|
||||
- In a multi‑node network, use Redis gossip backend and configure `trusted_proposers` with all authority addresses.
|
||||
|
||||
@@ -2,13 +2,41 @@
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
VENV_PYTHON="$ROOT_DIR/.venv/bin/python"
|
||||
if [ ! -x "$VENV_PYTHON" ]; then
|
||||
echo "[devnet] Virtualenv not found at $VENV_PYTHON. Please create it: python -m venv .venv && .venv/bin/pip install -r requirements.txt"
|
||||
exit 1
|
||||
fi
|
||||
export PYTHONPATH="${ROOT_DIR}/src:${ROOT_DIR}/scripts:${PYTHONPATH:-}"
|
||||
|
||||
GENESIS_PATH="${ROOT_DIR}/data/devnet/genesis.json"
|
||||
python "${ROOT_DIR}/scripts/make_genesis.py" --output "${GENESIS_PATH}" --force
|
||||
GENESIS_PATH="data/devnet/genesis.json"
|
||||
ALLOCATIONS_PATH="data/devnet/allocations.json"
|
||||
PROPOSER_ADDRESS="ait15v2cdlz5a3uy3wfurgh6m957kahnhhprdq7fy9m6eay05mvrv4jsyx4sks"
|
||||
"$VENV_PYTHON" "scripts/make_genesis.py" \
|
||||
--output "$GENESIS_PATH" \
|
||||
--force \
|
||||
--allocations "$ALLOCATIONS_PATH" \
|
||||
--authorities "$PROPOSER_ADDRESS" \
|
||||
--chain-id "ait-devnet"
|
||||
|
||||
echo "[devnet] Generated genesis at ${GENESIS_PATH}"
|
||||
|
||||
# Set environment for devnet
|
||||
export chain_id="ait-devnet"
|
||||
export supported_chains="ait-devnet"
|
||||
export proposer_id="${PROPOSER_ADDRESS}"
|
||||
export mint_per_unit=0
|
||||
export coordinator_ratio=0.05
|
||||
export db_path="./data/${chain_id}/chain.db"
|
||||
export trusted_proposers="${PROPOSER_ADDRESS}"
|
||||
export gossip_backend="memory"
|
||||
|
||||
# Optional: if you have a proposer private key for block signing (future), set PROPOSER_KEY
|
||||
# export PROPOSER_KEY="..."
|
||||
|
||||
echo "[devnet] Environment configured: chain_id=${chain_id}, proposer_id=${proposer_id}"
|
||||
|
||||
declare -a CHILD_PIDS=()
|
||||
cleanup() {
|
||||
for pid in "${CHILD_PIDS[@]}"; do
|
||||
@@ -19,18 +47,19 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
python -m aitbc_chain.main &
|
||||
"$VENV_PYTHON" -m aitbc_chain.main &
|
||||
CHILD_PIDS+=($!)
|
||||
echo "[devnet] Blockchain node started (PID ${CHILD_PIDS[-1]})"
|
||||
|
||||
sleep 1
|
||||
|
||||
python -m uvicorn aitbc_chain.app:app --host 127.0.0.1 --port 8026 --log-level info &
|
||||
"$VENV_PYTHON" -m uvicorn aitbc_chain.app:app --host 127.0.0.1 --port 8026 --log-level info &
|
||||
CHILD_PIDS+=($!)
|
||||
echo "[devnet] RPC API serving at http://127.0.0.1:8026"
|
||||
echo "[devnet] RPC API serving at http://127.0.0.1:8026"
|
||||
|
||||
python -m uvicorn mock_coordinator:app --host 127.0.0.1 --port 8090 --log-level info &
|
||||
CHILD_PIDS+=($!)
|
||||
echo "[devnet] Mock coordinator serving at http://127.0.0.1:8090"
|
||||
# Optional: mock coordinator for devnet only
|
||||
# "$VENV_PYTHON" -m uvicorn mock_coordinator:app --host 127.0.0.1 --port 8090 --log-level info &
|
||||
# CHILD_PIDS+=($!)
|
||||
# echo "[devnet] Mock coordinator serving at http://127.0.0.1:8090"
|
||||
|
||||
wait
|
||||
|
||||
186
apps/blockchain-node/scripts/keystore.py
Normal file
186
apps/blockchain-node/scripts/keystore.py
Normal file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Production key management for AITBC blockchain.
|
||||
|
||||
Generates ed25519 keypairs and stores them in an encrypted JSON keystore
|
||||
(Ethereum-style web3 keystore). Supports multiple wallets (treasury, proposer, etc.)
|
||||
|
||||
Usage:
|
||||
python keystore.py --name treasury --create --password <secret>
|
||||
python keystore.py --name proposer --create --password <secret>
|
||||
python keystore.py --name treasury --show
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
# Uses Cryptography library for ed25519 and encryption
|
||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
# Address encoding: bech32m (HRP 'ait')
|
||||
from bech32 import bech32_encode, convertbits
|
||||
|
||||
|
||||
def generate_address(public_key_bytes: bytes) -> str:
|
||||
"""Generate a bech32m address from a public key.
|
||||
1. Take SHA256 of the public key (produces 32 bytes)
|
||||
2. Convert to 5-bit groups (bech32)
|
||||
3. Encode with HRP 'ait'
|
||||
"""
|
||||
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
||||
digest.update(public_key_bytes)
|
||||
hashed = digest.finalize()
|
||||
# Convert to 5-bit words for bech32
|
||||
data = convertbits(hashed, 8, 5, True)
|
||||
return bech32_encode("ait", data)
|
||||
|
||||
|
||||
def encrypt_private_key(private_key_bytes: bytes, password: str, salt: bytes) -> Dict[str, Any]:
|
||||
"""Encrypt a private key using AES-GCM, wrapped in a JSON keystore."""
|
||||
# Derive key from password using PBKDF2
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=salt,
|
||||
iterations=100_000,
|
||||
backend=default_backend()
|
||||
)
|
||||
key = kdf.derive(password.encode('utf-8'))
|
||||
|
||||
# Encrypt with AES-GCM
|
||||
aesgcm = AESGCM(key)
|
||||
nonce = os.urandom(12)
|
||||
encrypted = aesgcm.encrypt(nonce, private_key_bytes, None)
|
||||
|
||||
return {
|
||||
"crypto": {
|
||||
"cipher": "aes-256-gcm",
|
||||
"cipherparams": {"nonce": nonce.hex()},
|
||||
"ciphertext": encrypted.hex(),
|
||||
"kdf": "pbkdf2",
|
||||
"kdfparams": {
|
||||
"dklen": 32,
|
||||
"salt": salt.hex(),
|
||||
"c": 100_000,
|
||||
"prf": "hmac-sha256"
|
||||
},
|
||||
"mac": "TODO" # In production, compute MAC over ciphertext and KDF params
|
||||
},
|
||||
"address": None, # to be filled
|
||||
"keytype": "ed25519",
|
||||
"version": 1
|
||||
}
|
||||
|
||||
|
||||
def generate_keypair(name: str, password: str, keystore_dir: Path) -> Dict[str, Any]:
|
||||
"""Generate a new ed25519 keypair and store in keystore."""
|
||||
salt = os.urandom(32)
|
||||
private_key = ed25519.Ed25519PrivateKey.generate()
|
||||
public_key = private_key.public_key()
|
||||
private_bytes = private_key.private_bytes(
|
||||
encoding=serialization.Encoding.Raw,
|
||||
format=serialization.PrivateFormat.Raw,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
)
|
||||
public_bytes = public_key.public_bytes(
|
||||
encoding=serialization.Encoding.Raw,
|
||||
format=serialization.PublicFormat.Raw
|
||||
)
|
||||
address = generate_address(public_bytes)
|
||||
|
||||
keystore = encrypt_private_key(private_bytes, password, salt)
|
||||
keystore["address"] = address
|
||||
|
||||
keystore_file = keystore_dir / f"{name}.json"
|
||||
keystore_dir.mkdir(parents=True, exist_ok=True)
|
||||
with open(keystore_file, 'w') as f:
|
||||
json.dump(keystore, f, indent=2)
|
||||
os.chmod(keystore_file, 0o600)
|
||||
|
||||
print(f"Generated {name} keypair")
|
||||
print(f" Address: {address}")
|
||||
print(f" Keystore: {keystore_file}")
|
||||
return keystore
|
||||
|
||||
|
||||
def show_keyinfo(keystore_file: Path, password: str) -> None:
|
||||
"""Decrypt and show key info (address, public key)."""
|
||||
with open(keystore_file) as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Derive key from password
|
||||
crypto = data["crypto"]
|
||||
kdfparams = crypto["kdfparams"]
|
||||
salt = bytes.fromhex(kdfparams["salt"])
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=salt,
|
||||
iterations=kdfparams["c"],
|
||||
backend=default_backend()
|
||||
)
|
||||
key = kdf.derive(password.encode('utf-8'))
|
||||
|
||||
# Decrypt private key
|
||||
nonce = bytes.fromhex(crypto["cipherparams"]["nonce"])
|
||||
ciphertext = bytes.fromhex(crypto["ciphertext"])
|
||||
aesgcm = AESGCM(key)
|
||||
private_bytes = aesgcm.decrypt(nonce, ciphertext, None)
|
||||
private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_bytes)
|
||||
public_bytes = private_key.public_key().public_bytes(
|
||||
encoding=serialization.Encoding.Raw,
|
||||
format=serialization.PublicFormat.Raw
|
||||
)
|
||||
address = generate_address(public_bytes)
|
||||
|
||||
print(f"Keystore: {keystore_file}")
|
||||
print(f"Address: {address}")
|
||||
print(f"Public key (hex): {public_bytes.hex()}")
|
||||
|
||||
|
||||
def main():
|
||||
from getpass import getpass
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
|
||||
parser = argparse.ArgumentParser(description="Production keystore management")
|
||||
parser.add_argument("--name", required=True, help="Key name (e.g., treasury, proposer)")
|
||||
parser.add_argument("--create", action="store_true", help="Generate new keypair")
|
||||
parser.add_argument("--show", action="store_true", help="Show address/public key (prompt for password)")
|
||||
parser.add_argument("--password", help="Password (avoid using in CLI; prefer prompt or env)")
|
||||
parser.add_argument("--keystore-dir", type=Path, default=Path("/opt/aitbc/keystore"), help="Keystore directory")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.create:
|
||||
pwd = args.password or os.getenv("KEYSTORE_PASSWORD") or getpass("New password: ")
|
||||
if not pwd:
|
||||
print("Password required")
|
||||
sys.exit(1)
|
||||
generate_keypair(args.name, pwd, args.keystore_dir)
|
||||
|
||||
elif args.show:
|
||||
pwd = args.password or os.getenv("KEYSTORE_PASSWORD") or getpass("Password: ")
|
||||
if not pwd:
|
||||
print("Password required")
|
||||
sys.exit(1)
|
||||
keystore_file = args.keystore_dir / f"{args.name}.json"
|
||||
if not keystore_file.exists():
|
||||
print(f"Keystore not found: {keystore_file}")
|
||||
sys.exit(1)
|
||||
show_keyinfo(keystore_file, pwd)
|
||||
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
85
apps/blockchain-node/scripts/mainnet_up.sh
Executable file
85
apps/blockchain-node/scripts/mainnet_up.sh
Executable file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
VENV_PYTHON="$ROOT_DIR/.venv/bin/python"
|
||||
if [ ! -x "$VENV_PYTHON" ]; then
|
||||
echo "[mainnet] Virtualenv not found at $VENV_PYTHON. Please create it: python -m venv .venv && .venv/bin/pip install -r requirements.txt"
|
||||
exit 1
|
||||
fi
|
||||
export PYTHONPATH="${ROOT_DIR}/src:${ROOT_DIR}/scripts:${PYTHONPATH:-}"
|
||||
|
||||
# Load production environment
|
||||
if [ -f ".env.production" ]; then
|
||||
set -a
|
||||
source .env.production
|
||||
set +a
|
||||
fi
|
||||
|
||||
CHAIN_ID="${chain_id:-ait-mainnet}"
|
||||
export chain_id="$CHAIN_ID"
|
||||
export supported_chains="${supported_chains:-$CHAIN_ID}"
|
||||
|
||||
# Proposer ID: should be the genesis wallet address (from keystore/aitbc1genesis.json)
|
||||
# If not set in env, derive from keystore
|
||||
if [ -z "${proposer_id:-}" ]; then
|
||||
if [ -f "keystore/aitbc1genesis.json" ]; then
|
||||
PROPOSER_ID=$(grep -o '"address": "[^"]*"' keystore/aitbc1genesis.json | cut -d'"' -f4)
|
||||
if [ -n "$PROPOSER_ID" ]; then
|
||||
export proposer_id="$PROPOSER_ID"
|
||||
else
|
||||
echo "[mainnet] ERROR: Could not derive proposer_id from keystore. Set proposer_id in .env.production"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "[mainnet] ERROR: keystore/aitbc1genesis.json not found. Run setup_production.py first."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
export proposer_id
|
||||
fi
|
||||
|
||||
# Ensure mint_per_unit=0 for fixed supply
|
||||
export mint_per_unit=0
|
||||
export coordinator_ratio=0.05
|
||||
export db_path="./data/${CHAIN_ID}/chain.db"
|
||||
export trusted_proposers="${trusted_proposers:-$proposer_id}"
|
||||
export gossip_backend="${gossip_backend:-memory}"
|
||||
|
||||
# Optional: load proposer private key from keystore if block signing is implemented
|
||||
# export PROPOSER_KEY="..." # Not yet used; future feature
|
||||
|
||||
echo "[mainnet] Starting blockchain node for ${CHAIN_ID}"
|
||||
echo " proposer_id: $proposer_id"
|
||||
echo " db_path: $db_path"
|
||||
echo " gossip: $gossip_backend"
|
||||
|
||||
# Check that genesis exists
|
||||
GENESIS_PATH="data/${CHAIN_ID}/genesis.json"
|
||||
if [ ! -f "$GENESIS_PATH" ]; then
|
||||
echo "[mainnet] Genesis not found at $GENESIS_PATH. Run setup_production.py first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -a CHILD_PIDS=()
|
||||
cleanup() {
|
||||
for pid in "${CHILD_PIDS[@]}"; do
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
kill "$pid" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
"$VENV_PYTHON" -m aitbc_chain.main &
|
||||
CHILD_PIDS+=($!)
|
||||
echo "[mainnet] Blockchain node started (PID ${CHILD_PIDS[-1]})"
|
||||
|
||||
sleep 2
|
||||
|
||||
"$VENV_PYTHON" -m uvicorn aitbc_chain.app:app --host 127.0.0.1 --port 8026 --log-level info &
|
||||
CHILD_PIDS+=($!)
|
||||
echo "[mainnet] RPC API serving at http://127.0.0.1:8026"
|
||||
|
||||
wait
|
||||
@@ -1,5 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate a deterministic devnet genesis file for the blockchain node."""
|
||||
"""Generate a production-ready genesis file with fixed allocations.
|
||||
|
||||
This replaces the old devnet faucet model. Genesis now defines a fixed
|
||||
initial coin supply allocated to specific addresses. No admin minting
|
||||
is allowed; the total supply is immutable after genesis.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -7,75 +12,79 @@ import argparse
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any
|
||||
|
||||
DEFAULT_GENESIS = {
|
||||
"chain_id": "ait-devnet",
|
||||
"timestamp": None, # populated at runtime
|
||||
"params": {
|
||||
"mint_per_unit": 1000,
|
||||
"coordinator_ratio": 0.05,
|
||||
"base_fee": 10,
|
||||
"fee_per_byte": 1,
|
||||
},
|
||||
"accounts": [
|
||||
{
|
||||
"address": "ait1faucet000000000000000000000000000000000",
|
||||
"balance": 1_000_000_000,
|
||||
"nonce": 0,
|
||||
}
|
||||
],
|
||||
"authorities": [
|
||||
{
|
||||
"address": "ait1devproposer000000000000000000000000000000",
|
||||
"weight": 1,
|
||||
}
|
||||
],
|
||||
# Chain parameters - these are on-chain economic settings
|
||||
CHAIN_PARAMS = {
|
||||
"mint_per_unit": 0, # No new minting after genesis
|
||||
"coordinator_ratio": 0.05,
|
||||
"base_fee": 10,
|
||||
"fee_per_byte": 1,
|
||||
}
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Generate devnet genesis data")
|
||||
parser = argparse.ArgumentParser(description="Generate production genesis data")
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
type=Path,
|
||||
default=Path("data/devnet/genesis.json"),
|
||||
help="Path to write the generated genesis file (default: data/devnet/genesis.json)",
|
||||
help="Path to write the genesis file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="Overwrite the genesis file if it already exists.",
|
||||
help="Overwrite existing genesis file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--faucet-address",
|
||||
default="ait1faucet000000000000000000000000000000000",
|
||||
help="Address seeded with devnet funds.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--faucet-balance",
|
||||
type=int,
|
||||
default=1_000_000_000,
|
||||
help="Faucet balance in smallest units.",
|
||||
"--allocations",
|
||||
type=Path,
|
||||
required=True,
|
||||
help="JSON file mapping addresses to initial balances (smallest units)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--authorities",
|
||||
nargs="*",
|
||||
default=["ait1devproposer000000000000000000000000000000"],
|
||||
help="Authority addresses included in the genesis file.",
|
||||
required=True,
|
||||
help="List of PoA authority addresses (proposer/validators)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--chain-id",
|
||||
default="ait-devnet",
|
||||
help="Chain ID (default: ait-devnet)",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def build_genesis(args: argparse.Namespace) -> dict:
|
||||
genesis = json.loads(json.dumps(DEFAULT_GENESIS)) # deep copy via JSON
|
||||
genesis["timestamp"] = int(time.time())
|
||||
genesis["accounts"][0]["address"] = args.faucet_address
|
||||
genesis["accounts"][0]["balance"] = args.faucet_balance
|
||||
genesis["authorities"] = [
|
||||
{"address": address, "weight": 1}
|
||||
for address in args.authorities
|
||||
def load_allocations(path: Path) -> List[Dict[str, Any]]:
|
||||
"""Load address allocations from a JSON file.
|
||||
Expected format:
|
||||
[
|
||||
{"address": "ait1...", "balance": 1000000000, "nonce": 0}
|
||||
]
|
||||
return genesis
|
||||
"""
|
||||
with open(path) as f:
|
||||
data = json.load(f)
|
||||
if not isinstance(data, list):
|
||||
raise ValueError("allocations must be a list of objects")
|
||||
# Validate required fields
|
||||
for item in data:
|
||||
if "address" not in item or "balance" not in item:
|
||||
raise ValueError(f"Allocation missing required fields: {item}")
|
||||
return data
|
||||
|
||||
|
||||
def build_genesis(chain_id: str, allocations: List[Dict[str, Any]], authorities: List[str]) -> dict:
|
||||
"""Construct the genesis block specification."""
|
||||
timestamp = int(time.time())
|
||||
return {
|
||||
"chain_id": chain_id,
|
||||
"timestamp": timestamp,
|
||||
"params": CHAIN_PARAMS.copy(),
|
||||
"allocations": allocations, # Renamed from 'accounts' to avoid confusion
|
||||
"authorities": [
|
||||
{"address": addr, "weight": 1} for addr in authorities
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def write_genesis(path: Path, data: dict, force: bool) -> None:
|
||||
@@ -88,8 +97,12 @@ def write_genesis(path: Path, data: dict, force: bool) -> None:
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
genesis = build_genesis(args)
|
||||
allocations = load_allocations(args.allocations)
|
||||
genesis = build_genesis(args.chain_id, allocations, args.authorities)
|
||||
write_genesis(args.output, genesis, args.force)
|
||||
total = sum(a["balance"] for a in allocations)
|
||||
print(f"[genesis] Total supply: {total} (fixed, no future minting)")
|
||||
print("[genesis] IMPORTANT: Keep the private keys for these addresses secure!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
202
apps/blockchain-node/scripts/setup_production.py
Normal file
202
apps/blockchain-node/scripts/setup_production.py
Normal file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Production setup generator for AITBC blockchain.
|
||||
Creates two wallets:
|
||||
- aitbc1genesis: Treasury wallet holding all initial supply (1B AIT)
|
||||
- aitbc1treasury: Spending wallet (for transactions, can receive from genesis)
|
||||
|
||||
No admin minting; fixed supply at genesis.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import string
|
||||
from pathlib import Path
|
||||
|
||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
||||
from cryptography.hazmat.primitives import serialization, hashes
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
from bech32 import bech32_encode, convertbits
|
||||
|
||||
|
||||
def random_password(length: int = 32) -> str:
|
||||
"""Generate a strong random password."""
|
||||
alphabet = string.ascii_letters + string.digits + string.punctuation
|
||||
return ''.join(secrets.choice(alphabet) for _ in range(length))
|
||||
|
||||
|
||||
def generate_address(public_key_bytes: bytes) -> str:
|
||||
"""Bech32m address with HRP 'ait'."""
|
||||
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
||||
digest.update(public_key_bytes)
|
||||
hashed = digest.finalize()
|
||||
data = convertbits(hashed, 8, 5, True)
|
||||
return bech32_encode("ait", data)
|
||||
|
||||
|
||||
def encrypt_private_key(private_bytes: bytes, password: str, salt: bytes) -> dict:
|
||||
"""Web3-style keystore encryption (AES-GCM + PBKDF2)."""
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=salt,
|
||||
iterations=100_000,
|
||||
backend=default_backend()
|
||||
)
|
||||
key = kdf.derive(password.encode('utf-8'))
|
||||
|
||||
aesgcm = AESGCM(key)
|
||||
nonce = os.urandom(12)
|
||||
ciphertext = aesgcm.encrypt(nonce, private_bytes, None)
|
||||
|
||||
return {
|
||||
"crypto": {
|
||||
"cipher": "aes-256-gcm",
|
||||
"cipherparams": {"nonce": nonce.hex()},
|
||||
"ciphertext": ciphertext.hex(),
|
||||
"kdf": "pbkdf2",
|
||||
"kdfparams": {
|
||||
"dklen": 32,
|
||||
"salt": salt.hex(),
|
||||
"c": 100_000,
|
||||
"prf": "hmac-sha256"
|
||||
},
|
||||
"mac": "TODO" # In production, compute proper MAC
|
||||
},
|
||||
"address": None,
|
||||
"keytype": "ed25519",
|
||||
"version": 1
|
||||
}
|
||||
|
||||
|
||||
def generate_wallet(name: str, password: str, keystore_dir: Path) -> dict:
|
||||
"""Generate ed25519 keypair and return wallet info."""
|
||||
private_key = ed25519.Ed25519PrivateKey.generate()
|
||||
public_key = private_key.public_key()
|
||||
|
||||
private_bytes = private_key.private_bytes(
|
||||
encoding=serialization.Encoding.Raw,
|
||||
format=serialization.PrivateFormat.Raw,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
)
|
||||
public_bytes = public_key.public_bytes(
|
||||
encoding=serialization.Encoding.Raw,
|
||||
format=serialization.PublicFormat.Raw
|
||||
)
|
||||
address = generate_address(public_bytes)
|
||||
|
||||
salt = os.urandom(32)
|
||||
keystore = encrypt_private_key(private_bytes, password, salt)
|
||||
keystore["address"] = address
|
||||
|
||||
keystore_file = keystore_dir / f"{name}.json"
|
||||
with open(keystore_file, 'w') as f:
|
||||
json.dump(keystore, f, indent=2)
|
||||
os.chmod(keystore_file, 0o600)
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"address": address,
|
||||
"keystore_file": str(keystore_file),
|
||||
"public_key_hex": public_bytes.hex()
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Production blockchain setup")
|
||||
parser.add_argument("--base-dir", type=Path, default=Path("/opt/aitbc/apps/blockchain-node"),
|
||||
help="Blockchain node base directory")
|
||||
parser.add_argument("--chain-id", default="ait-mainnet", help="Chain ID")
|
||||
parser.add_argument("--total-supply", type=int, default=1_000_000_000,
|
||||
help="Total token supply (smallest units)")
|
||||
args = parser.parse_args()
|
||||
|
||||
base_dir = args.base_dir
|
||||
keystore_dir = base_dir / "keystore"
|
||||
data_dir = base_dir / "data" / args.chain_id
|
||||
|
||||
keystore_dir.mkdir(parents=True, exist_ok=True)
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Generate strong random password and save it
|
||||
password = random_password(32)
|
||||
password_file = keystore_dir / ".password"
|
||||
with open(password_file, 'w') as f:
|
||||
f.write(password + "\n")
|
||||
os.chmod(password_file, 0o600)
|
||||
|
||||
print(f"[setup] Generated keystore password and saved to {password_file}")
|
||||
|
||||
# Generate two wallets
|
||||
wallets = []
|
||||
for suffix in ["genesis", "treasury"]:
|
||||
name = f"aitbc1{suffix}"
|
||||
info = generate_wallet(name, password, keystore_dir)
|
||||
# Store both the full name and suffix for lookup
|
||||
info['suffix'] = suffix
|
||||
wallets.append(info)
|
||||
print(f"[setup] Created wallet: {name}")
|
||||
print(f" Address: {info['address']}")
|
||||
print(f" Keystore: {info['keystore_file']}")
|
||||
|
||||
# Create allocations: all supply to genesis wallet, treasury gets 0 (for spending from genesis)
|
||||
genesis_wallet = next(w for w in wallets if w['suffix'] == 'genesis')
|
||||
treasury_wallet = next(w for w in wallets if w['suffix'] == 'treasury')
|
||||
allocations = [
|
||||
{
|
||||
"address": genesis_wallet["address"],
|
||||
"balance": args.total_supply,
|
||||
"nonce": 0
|
||||
},
|
||||
{
|
||||
"address": treasury_wallet["address"],
|
||||
"balance": 0,
|
||||
"nonce": 0
|
||||
}
|
||||
]
|
||||
|
||||
allocations_file = data_dir / "allocations.json"
|
||||
with open(allocations_file, 'w') as f:
|
||||
json.dump(allocations, f, indent=2)
|
||||
print(f"[setup] Wrote allocations to {allocations_file}")
|
||||
|
||||
# Create genesis.json via make_genesis script
|
||||
import subprocess
|
||||
genesis_file = data_dir / "genesis.json"
|
||||
python_exec = base_dir / ".venv" / "bin" / "python"
|
||||
if not python_exec.exists():
|
||||
python_exec = "python3" # fallback
|
||||
result = subprocess.run([
|
||||
str(python_exec), str(base_dir / "scripts" / "make_genesis.py"),
|
||||
"--output", str(genesis_file),
|
||||
"--force",
|
||||
"--allocations", str(allocations_file),
|
||||
"--authorities", genesis_wallet["address"],
|
||||
"--chain-id", args.chain_id
|
||||
], capture_output=True, text=True, cwd=str(base_dir))
|
||||
if result.returncode != 0:
|
||||
print(f"[setup] Genesis generation failed: {result.stderr}")
|
||||
return 1
|
||||
print(f"[setup] Created genesis file at {genesis_file}")
|
||||
print(result.stdout.strip())
|
||||
|
||||
print("\n[setup] Production setup complete!")
|
||||
print(f" Chain ID: {args.chain_id}")
|
||||
print(f" Total supply: {args.total_supply} (fixed)")
|
||||
print(f" Genesis wallet: {genesis_wallet['address']}")
|
||||
print(f" Treasury wallet: {treasury_wallet['address']}")
|
||||
print(f" Keystore password: stored in {password_file}")
|
||||
print("\n[IMPORTANT] Keep the keystore files and password secure!")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
@@ -16,7 +16,7 @@ from .mempool import init_mempool
|
||||
from .metrics import metrics_registry
|
||||
from .rpc.router import router as rpc_router
|
||||
from .rpc.websocket import router as websocket_router
|
||||
from .escrow_routes import router as escrow_router
|
||||
# from .escrow_routes import router as escrow_router # Not yet implemented
|
||||
|
||||
_app_logger = get_logger("aitbc_chain.app")
|
||||
|
||||
@@ -132,7 +132,7 @@ def create_app() -> FastAPI:
|
||||
# Include routers
|
||||
app.include_router(rpc_router, prefix="/rpc", tags=["rpc"])
|
||||
app.include_router(websocket_router, prefix="/rpc")
|
||||
app.include_router(escrow_router, prefix="/rpc")
|
||||
# app.include_router(escrow_router, prefix="/rpc") # Disabled until escrow routes are implemented
|
||||
|
||||
# Metrics and health endpoints
|
||||
metrics_router = APIRouter()
|
||||
|
||||
180
apps/blockchain-node/src/aitbc_chain/chain_sync.py
Normal file
180
apps/blockchain-node/src/aitbc_chain/chain_sync.py
Normal file
@@ -0,0 +1,180 @@
|
||||
#!/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):
|
||||
self.redis_url = redis_url
|
||||
self.node_id = node_id
|
||||
self.rpc_port = rpc_port
|
||||
self._stop_event = asyncio.Event()
|
||||
self._redis = None
|
||||
|
||||
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
|
||||
broadcast_task = asyncio.create_task(self._broadcast_blocks())
|
||||
|
||||
# Start block receiving task
|
||||
receive_task = asyncio.create_task(self._receive_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
|
||||
|
||||
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://127.0.0.1:{self.rpc_port}/rpc/head") as resp:
|
||||
if resp.status == 200:
|
||||
head_data = await resp.json()
|
||||
current_height = head_data.get('height', 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}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in block broadcast: {e}")
|
||||
|
||||
await asyncio.sleep(2) # Check every 2 seconds
|
||||
|
||||
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")
|
||||
|
||||
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://127.0.0.1:{self.rpc_port}/rpc/blocks?start={height}&end={height}") as resp:
|
||||
if resp.status == 200:
|
||||
blocks_data = await resp.json()
|
||||
blocks = blocks_data.get('blocks', [])
|
||||
return blocks[0] if blocks else None
|
||||
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
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(
|
||||
f"http://127.0.0.1:{self.rpc_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')}")
|
||||
else:
|
||||
logger.warning(f"Failed to import block: {resp.status}")
|
||||
|
||||
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):
|
||||
"""Run chain synchronization service"""
|
||||
service = ChainSyncService(redis_url, node_id, rpc_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")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
try:
|
||||
asyncio.run(run_chain_sync(args.redis, args.node_id, args.rpc_port))
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Chain sync service stopped by user")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -18,7 +18,7 @@ class ProposerConfig(BaseModel):
|
||||
class ChainSettings(BaseSettings):
|
||||
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", case_sensitive=False)
|
||||
|
||||
chain_id: str = "ait-devnet"
|
||||
chain_id: str = ""
|
||||
supported_chains: str = "ait-devnet" # Comma-separated list of supported chain IDs
|
||||
db_path: Path = Path("./data/chain.db")
|
||||
|
||||
@@ -28,10 +28,10 @@ class ChainSettings(BaseSettings):
|
||||
p2p_bind_host: str = "127.0.0.2"
|
||||
p2p_bind_port: int = 7070
|
||||
|
||||
proposer_id: str = "ait-devnet-proposer"
|
||||
proposer_id: str = ""
|
||||
proposer_key: Optional[str] = None
|
||||
|
||||
mint_per_unit: int = 1000
|
||||
mint_per_unit: int = 0 # No new minting after genesis for production
|
||||
coordinator_ratio: float = 0.05
|
||||
|
||||
block_time_seconds: int = 2
|
||||
@@ -58,5 +58,9 @@ class ChainSettings(BaseSettings):
|
||||
gossip_backend: str = "memory"
|
||||
gossip_broadcast_url: Optional[str] = None
|
||||
|
||||
# Keystore for proposer private key (future block signing)
|
||||
keystore_path: Path = Path("./keystore")
|
||||
keystore_password_file: Path = Path("./keystore/.password")
|
||||
|
||||
|
||||
settings = ChainSettings()
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import asyncio
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Callable, ContextManager, Optional
|
||||
|
||||
from sqlmodel import Session, select
|
||||
@@ -9,7 +11,7 @@ from sqlmodel import Session, select
|
||||
from ..logger import get_logger
|
||||
from ..metrics import metrics_registry
|
||||
from ..config import ProposerConfig
|
||||
from ..models import Block
|
||||
from ..models import Block, Account
|
||||
from ..gossip import gossip_broker
|
||||
|
||||
_METRIC_KEY_SANITIZE = re.compile(r"[^a-zA-Z0-9_]")
|
||||
@@ -118,10 +120,11 @@ class PoAProposer:
|
||||
return
|
||||
|
||||
async def _propose_block(self) -> None:
|
||||
# Check internal mempool
|
||||
# Check internal mempool - but produce empty blocks to keep chain moving
|
||||
from ..mempool import get_mempool
|
||||
if get_mempool().size(self._config.chain_id) == 0:
|
||||
return
|
||||
mempool_size = get_mempool().size(self._config.chain_id)
|
||||
if mempool_size == 0:
|
||||
self._logger.debug("No transactions in mempool, producing empty block")
|
||||
|
||||
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()
|
||||
@@ -199,14 +202,17 @@ class PoAProposer:
|
||||
height=0,
|
||||
hash=block_hash,
|
||||
parent_hash="0x00",
|
||||
proposer="genesis",
|
||||
proposer=self._config.proposer_id, # Use configured proposer as genesis proposer
|
||||
timestamp=timestamp,
|
||||
tx_count=0,
|
||||
state_root=None,
|
||||
)
|
||||
session.add(genesis)
|
||||
session.commit()
|
||||
|
||||
|
||||
# Initialize accounts from genesis allocations file (if present)
|
||||
await self._initialize_genesis_allocations(session)
|
||||
|
||||
# Broadcast genesis block for initial sync
|
||||
await gossip_broker.publish(
|
||||
"blocks",
|
||||
@@ -222,6 +228,33 @@ class PoAProposer:
|
||||
}
|
||||
)
|
||||
|
||||
async def _initialize_genesis_allocations(self, session: Session) -> None:
|
||||
"""Create Account entries from the genesis allocations file."""
|
||||
# Look for genesis file relative to project root: data/{chain_id}/genesis.json
|
||||
# Alternatively, use a path from config (future improvement)
|
||||
genesis_path = Path(f"./data/{self._config.chain_id}/genesis.json")
|
||||
if not genesis_path.exists():
|
||||
self._logger.warning("Genesis allocations file not found; skipping account initialization", extra={"path": str(genesis_path)})
|
||||
return
|
||||
|
||||
with open(genesis_path) as f:
|
||||
genesis_data = json.load(f)
|
||||
|
||||
allocations = genesis_data.get("allocations", [])
|
||||
created = 0
|
||||
for alloc in allocations:
|
||||
addr = alloc["address"]
|
||||
balance = int(alloc["balance"])
|
||||
nonce = int(alloc.get("nonce", 0))
|
||||
# Check if account already exists (idempotent)
|
||||
acct = session.get(Account, (self._config.chain_id, addr))
|
||||
if acct is None:
|
||||
acct = Account(chain_id=self._config.chain_id, address=addr, balance=balance, nonce=nonce)
|
||||
session.add(acct)
|
||||
created += 1
|
||||
session.commit()
|
||||
self._logger.info("Initialized genesis accounts", extra={"count": created, "total": len(allocations)})
|
||||
|
||||
def _fetch_chain_head(self) -> Optional[Block]:
|
||||
with self._session_factory() as session:
|
||||
return session.exec(select(Block).order_by(Block.height.desc()).limit(1)).first()
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from .config import settings
|
||||
@@ -14,6 +17,73 @@ from .mempool import init_mempool
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
def _load_keystore_password() -> str:
|
||||
"""Load keystore password from file or environment."""
|
||||
pwd_file = settings.keystore_password_file
|
||||
if pwd_file.exists():
|
||||
return pwd_file.read_text().strip()
|
||||
env_pwd = os.getenv("KEYSTORE_PASSWORD")
|
||||
if env_pwd:
|
||||
return env_pwd
|
||||
raise RuntimeError(f"Keystore password not found. Set in {pwd_file} or KEYSTORE_PASSWORD env.")
|
||||
|
||||
def _load_private_key_from_keystore(keystore_dir: Path, password: str, target_address: Optional[str] = None) -> Optional[bytes]:
|
||||
"""Load an ed25519 private key from the keystore.
|
||||
If target_address is given, find the keystore file with matching address.
|
||||
Otherwise, return the first key found.
|
||||
"""
|
||||
if not keystore_dir.exists():
|
||||
return None
|
||||
for kf in keystore_dir.glob("*.json"):
|
||||
try:
|
||||
with open(kf) as f:
|
||||
data = json.load(f)
|
||||
addr = data.get("address")
|
||||
if target_address and addr != target_address:
|
||||
continue
|
||||
# Decrypt
|
||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
crypto = data["crypto"]
|
||||
kdfparams = crypto["kdfparams"]
|
||||
salt = bytes.fromhex(kdfparams["salt"])
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=salt,
|
||||
iterations=kdfparams["c"],
|
||||
backend=default_backend()
|
||||
)
|
||||
key = kdf.derive(password.encode('utf-8'))
|
||||
nonce = bytes.fromhex(crypto["cipherparams"]["nonce"])
|
||||
ciphertext = bytes.fromhex(crypto["ciphertext"])
|
||||
aesgcm = AESGCM(key)
|
||||
private_bytes = aesgcm.decrypt(nonce, ciphertext, None)
|
||||
# Verify it's ed25519
|
||||
priv_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_bytes)
|
||||
return private_bytes
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
# Attempt to load proposer private key from keystore if not set
|
||||
if not settings.proposer_key:
|
||||
try:
|
||||
pwd = _load_keystore_password()
|
||||
key_bytes = _load_private_key_from_keystore(settings.keystore_path, pwd, target_address=settings.proposer_id)
|
||||
if key_bytes:
|
||||
# Encode as hex for easy storage; not yet used for signing
|
||||
settings.proposer_key = key_bytes.hex()
|
||||
logger.info("Loaded proposer private key from keystore", extra={"proposer_id": settings.proposer_id})
|
||||
else:
|
||||
logger.warning("Proposer private key not found in keystore; block signing disabled", extra={"proposer_id": settings.proposer_id})
|
||||
except Exception as e:
|
||||
logger.warning("Failed to load proposer key from keystore", extra={"error": str(e)})
|
||||
|
||||
|
||||
class BlockchainNode:
|
||||
def __init__(self) -> None:
|
||||
@@ -33,7 +103,7 @@ class BlockchainNode:
|
||||
if isinstance(tx_data, str):
|
||||
import json
|
||||
tx_data = json.loads(tx_data)
|
||||
chain_id = tx_data.get("chain_id", "ait-devnet")
|
||||
chain_id = tx_data.get("chain_id", settings.chain_id)
|
||||
mempool.add(tx_data, chain_id=chain_id)
|
||||
except Exception as exc:
|
||||
logger.error(f"Error processing transaction from gossip: {exc}")
|
||||
@@ -51,7 +121,7 @@ class BlockchainNode:
|
||||
if isinstance(block_data, str):
|
||||
import json
|
||||
block_data = json.loads(block_data)
|
||||
chain_id = block_data.get("chain_id", "ait-devnet")
|
||||
chain_id = block_data.get("chain_id", settings.chain_id)
|
||||
logger.info(f"Importing block for chain {chain_id}: {block_data.get('height')}")
|
||||
sync = ChainSync(session_factory=session_scope, chain_id=chain_id)
|
||||
res = sync.import_block(block_data)
|
||||
|
||||
@@ -38,7 +38,10 @@ class InMemoryMempool:
|
||||
self._max_size = max_size
|
||||
self._min_fee = min_fee
|
||||
|
||||
def add(self, tx: Dict[str, Any], chain_id: str = "ait-devnet") -> str:
|
||||
def add(self, tx: Dict[str, Any], chain_id: str = None) -> str:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
fee = tx.get("fee", 0)
|
||||
if fee < self._min_fee:
|
||||
raise ValueError(f"Fee {fee} below minimum {self._min_fee}")
|
||||
@@ -59,11 +62,17 @@ class InMemoryMempool:
|
||||
metrics_registry.increment(f"mempool_tx_added_total_{chain_id}")
|
||||
return tx_hash
|
||||
|
||||
def list_transactions(self, chain_id: str = "ait-devnet") -> List[PendingTransaction]:
|
||||
def list_transactions(self, chain_id: str = None) -> List[PendingTransaction]:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
with self._lock:
|
||||
return list(self._transactions.values())
|
||||
|
||||
def drain(self, max_count: int, max_bytes: int, chain_id: str = "ait-devnet") -> List[PendingTransaction]:
|
||||
def drain(self, max_count: int, max_bytes: int, chain_id: str = None) -> List[PendingTransaction]:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
"""Drain transactions for block inclusion, prioritized by fee (highest first)."""
|
||||
with self._lock:
|
||||
sorted_txs = sorted(
|
||||
@@ -87,14 +96,20 @@ class InMemoryMempool:
|
||||
metrics_registry.increment(f"mempool_tx_drained_total_{chain_id}", float(len(result)))
|
||||
return result
|
||||
|
||||
def remove(self, tx_hash: str, chain_id: str = "ait-devnet") -> bool:
|
||||
def remove(self, tx_hash: str, chain_id: str = None) -> bool:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
with self._lock:
|
||||
removed = self._transactions.pop(tx_hash, None) is not None
|
||||
if removed:
|
||||
metrics_registry.set_gauge("mempool_size", float(len(self._transactions)))
|
||||
return removed
|
||||
|
||||
def size(self, chain_id: str = "ait-devnet") -> int:
|
||||
def size(self, chain_id: str = None) -> int:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
with self._lock:
|
||||
return len(self._transactions)
|
||||
|
||||
@@ -135,7 +150,10 @@ class DatabaseMempool:
|
||||
self._conn.execute("CREATE INDEX IF NOT EXISTS idx_mempool_fee ON mempool(fee DESC)")
|
||||
self._conn.commit()
|
||||
|
||||
def add(self, tx: Dict[str, Any], chain_id: str = "ait-devnet") -> str:
|
||||
def add(self, tx: Dict[str, Any], chain_id: str = None) -> str:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
fee = tx.get("fee", 0)
|
||||
if fee < self._min_fee:
|
||||
raise ValueError(f"Fee {fee} below minimum {self._min_fee}")
|
||||
@@ -169,7 +187,10 @@ class DatabaseMempool:
|
||||
self._update_gauge(chain_id)
|
||||
return tx_hash
|
||||
|
||||
def list_transactions(self, chain_id: str = "ait-devnet") -> List[PendingTransaction]:
|
||||
def list_transactions(self, chain_id: str = None) -> List[PendingTransaction]:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
with self._lock:
|
||||
rows = self._conn.execute(
|
||||
"SELECT tx_hash, content, fee, size_bytes, received_at FROM mempool WHERE chain_id = ? ORDER BY fee DESC, received_at ASC",
|
||||
@@ -182,7 +203,10 @@ class DatabaseMempool:
|
||||
) for r in rows
|
||||
]
|
||||
|
||||
def drain(self, max_count: int, max_bytes: int, chain_id: str = "ait-devnet") -> List[PendingTransaction]:
|
||||
def drain(self, max_count: int, max_bytes: int, chain_id: str = None) -> List[PendingTransaction]:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
with self._lock:
|
||||
rows = self._conn.execute(
|
||||
"SELECT tx_hash, content, fee, size_bytes, received_at FROM mempool WHERE chain_id = ? ORDER BY fee DESC, received_at ASC",
|
||||
@@ -214,7 +238,10 @@ class DatabaseMempool:
|
||||
self._update_gauge(chain_id)
|
||||
return result
|
||||
|
||||
def remove(self, tx_hash: str, chain_id: str = "ait-devnet") -> bool:
|
||||
def remove(self, tx_hash: str, chain_id: str = None) -> bool:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
with self._lock:
|
||||
cursor = self._conn.execute("DELETE FROM mempool WHERE chain_id = ? AND tx_hash = ?", (chain_id, tx_hash))
|
||||
self._conn.commit()
|
||||
@@ -223,11 +250,17 @@ class DatabaseMempool:
|
||||
self._update_gauge(chain_id)
|
||||
return removed
|
||||
|
||||
def size(self, chain_id: str = "ait-devnet") -> int:
|
||||
def size(self, chain_id: str = None) -> int:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
with self._lock:
|
||||
return self._conn.execute("SELECT COUNT(*) FROM mempool WHERE chain_id = ?", (chain_id,)).fetchone()[0]
|
||||
|
||||
def _update_gauge(self, chain_id: str = "ait-devnet") -> None:
|
||||
def _update_gauge(self, chain_id: str = None) -> None:
|
||||
from .config import settings
|
||||
if chain_id is None:
|
||||
chain_id = settings.chain_id
|
||||
count = self._conn.execute("SELECT COUNT(*) FROM mempool WHERE chain_id = ?", (chain_id,)).fetchone()[0]
|
||||
metrics_registry.set_gauge(f"mempool_size_{chain_id}", float(count))
|
||||
|
||||
|
||||
106
apps/blockchain-node/src/aitbc_chain/p2p_network.py
Normal file
106
apps/blockchain-node/src/aitbc_chain/p2p_network.py
Normal 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()
|
||||
@@ -18,6 +18,13 @@ from ..models import Account, Block, Receipt, Transaction
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def get_chain_id(chain_id: str = None) -> str:
|
||||
"""Get chain_id from parameter or use default from settings"""
|
||||
if chain_id is None:
|
||||
from ..config import settings
|
||||
return settings.chain_id
|
||||
return chain_id
|
||||
|
||||
|
||||
def _serialize_receipt(receipt: Receipt) -> Dict[str, Any]:
|
||||
return {
|
||||
@@ -63,7 +70,14 @@ class EstimateFeeRequest(BaseModel):
|
||||
|
||||
|
||||
@router.get("/head", summary="Get current chain head")
|
||||
async def get_head(chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def get_head(chain_id: str = None) -> Dict[str, Any]:
|
||||
"""Get current chain head"""
|
||||
from ..config import settings as cfg
|
||||
|
||||
# Use default chain_id from settings if not provided
|
||||
if chain_id is None:
|
||||
chain_id = cfg.chain_id
|
||||
|
||||
metrics_registry.increment("rpc_get_head_total")
|
||||
start = time.perf_counter()
|
||||
with session_scope() as session:
|
||||
@@ -157,7 +171,8 @@ async def get_blocks_range(start: int, end: int) -> Dict[str, Any]:
|
||||
|
||||
|
||||
@router.get("/tx/{tx_hash}", summary="Get transaction by hash")
|
||||
async def get_transaction(tx_hash: str, chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def get_transaction(tx_hash: str, chain_id: str = None) -> Dict[str, Any]:
|
||||
chain_id = get_chain_id(chain_id)
|
||||
metrics_registry.increment("rpc_get_transaction_total")
|
||||
start = time.perf_counter()
|
||||
with session_scope() as session:
|
||||
@@ -296,7 +311,7 @@ async def get_receipts(limit: int = 20, offset: int = 0) -> Dict[str, Any]:
|
||||
|
||||
|
||||
@router.get("/getBalance/{address}", summary="Get account balance")
|
||||
async def get_balance(address: str, chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def get_balance(address: str, chain_id: str = None) -> Dict[str, Any]:
|
||||
metrics_registry.increment("rpc_get_balance_total")
|
||||
start = time.perf_counter()
|
||||
with session_scope() as session:
|
||||
@@ -442,7 +457,7 @@ async def get_addresses(limit: int = 20, offset: int = 0, min_balance: int = 0)
|
||||
|
||||
|
||||
@router.post("/sendTx", summary="Submit a new transaction")
|
||||
async def send_transaction(request: TransactionRequest, chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def send_transaction(request: TransactionRequest, chain_id: str = None) -> Dict[str, Any]:
|
||||
metrics_registry.increment("rpc_send_tx_total")
|
||||
start = time.perf_counter()
|
||||
mempool = get_mempool()
|
||||
@@ -481,7 +496,7 @@ async def send_transaction(request: TransactionRequest, chain_id: str = "ait-dev
|
||||
|
||||
|
||||
@router.post("/submitReceipt", summary="Submit receipt claim transaction")
|
||||
async def submit_receipt(request: ReceiptSubmissionRequest, chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def submit_receipt(request: ReceiptSubmissionRequest, chain_id: str = None) -> Dict[str, Any]:
|
||||
metrics_registry.increment("rpc_submit_receipt_total")
|
||||
start = time.perf_counter()
|
||||
tx_payload = {
|
||||
@@ -539,7 +554,7 @@ class ImportBlockRequest(BaseModel):
|
||||
|
||||
|
||||
@router.post("/importBlock", summary="Import a block from a remote peer")
|
||||
async def import_block(request: ImportBlockRequest, chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def import_block(request: ImportBlockRequest, chain_id: str = None) -> Dict[str, Any]:
|
||||
from ..sync import ChainSync, ProposerSignatureValidator
|
||||
from ..config import settings as cfg
|
||||
|
||||
@@ -578,7 +593,7 @@ async def import_block(request: ImportBlockRequest, chain_id: str = "ait-devnet"
|
||||
|
||||
|
||||
@router.get("/syncStatus", summary="Get chain sync status")
|
||||
async def sync_status(chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def sync_status(chain_id: str = None) -> Dict[str, Any]:
|
||||
from ..sync import ChainSync
|
||||
from ..config import settings as cfg
|
||||
|
||||
@@ -588,7 +603,7 @@ async def sync_status(chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
|
||||
|
||||
@router.get("/info", summary="Get blockchain information")
|
||||
async def get_blockchain_info(chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def get_blockchain_info(chain_id: str = None) -> Dict[str, Any]:
|
||||
"""Get comprehensive blockchain information"""
|
||||
from ..config import settings as cfg
|
||||
|
||||
@@ -634,31 +649,45 @@ async def get_blockchain_info(chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
|
||||
|
||||
@router.get("/supply", summary="Get token supply information")
|
||||
async def get_token_supply(chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def get_token_supply(chain_id: str = None) -> Dict[str, Any]:
|
||||
"""Get token supply information"""
|
||||
from ..config import settings as cfg
|
||||
|
||||
# Use default chain_id from settings if not provided
|
||||
if chain_id is None:
|
||||
chain_id = cfg.chain_id
|
||||
|
||||
metrics_registry.increment("rpc_supply_total")
|
||||
start = time.perf_counter()
|
||||
|
||||
with session_scope() as session:
|
||||
# Simple implementation for now
|
||||
response = {
|
||||
"chain_id": chain_id,
|
||||
"total_supply": 1000000000, # 1 billion from genesis
|
||||
"circulating_supply": 0, # No transactions yet
|
||||
"faucet_balance": 1000000000, # All tokens in faucet
|
||||
"faucet_address": "ait1faucet000000000000000000000000000000000",
|
||||
"mint_per_unit": cfg.mint_per_unit,
|
||||
"total_accounts": 0
|
||||
}
|
||||
# Production implementation - no faucet in mainnet
|
||||
if chain_id == "ait-mainnet":
|
||||
response = {
|
||||
"chain_id": chain_id,
|
||||
"total_supply": 1000000000, # 1 billion from genesis
|
||||
"circulating_supply": 0, # No transactions yet
|
||||
"mint_per_unit": cfg.mint_per_unit,
|
||||
"total_accounts": 0
|
||||
}
|
||||
else:
|
||||
# Devnet with faucet
|
||||
response = {
|
||||
"chain_id": chain_id,
|
||||
"total_supply": 1000000000, # 1 billion from genesis
|
||||
"circulating_supply": 0, # No transactions yet
|
||||
"faucet_balance": 1000000000, # All tokens in faucet
|
||||
"faucet_address": "ait1faucet000000000000000000000000000000000",
|
||||
"mint_per_unit": cfg.mint_per_unit,
|
||||
"total_accounts": 0
|
||||
}
|
||||
|
||||
metrics_registry.observe("rpc_supply_duration_seconds", time.perf_counter() - start)
|
||||
return response
|
||||
|
||||
|
||||
@router.get("/validators", summary="List blockchain validators")
|
||||
async def get_validators(chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
async def get_validators(chain_id: str = None) -> Dict[str, Any]:
|
||||
"""List blockchain validators (authorities)"""
|
||||
from ..config import settings as cfg
|
||||
|
||||
@@ -690,7 +719,7 @@ async def get_validators(chain_id: str = "ait-devnet") -> Dict[str, Any]:
|
||||
|
||||
|
||||
@router.get("/state", summary="Get blockchain state information")
|
||||
async def get_chain_state(chain_id: str = "ait-devnet"):
|
||||
async def get_chain_state(chain_id: str = None):
|
||||
"""Get blockchain state information for a chain"""
|
||||
start = time.perf_counter()
|
||||
|
||||
@@ -710,7 +739,7 @@ async def get_chain_state(chain_id: str = "ait-devnet"):
|
||||
|
||||
|
||||
@router.get("/rpc/getBalance/{address}", summary="Get account balance")
|
||||
async def get_balance(address: str, chain_id: str = "ait-devnet"):
|
||||
async def get_balance(address: str, chain_id: str = None):
|
||||
"""Get account balance for a specific address"""
|
||||
start = time.perf_counter()
|
||||
|
||||
@@ -753,7 +782,7 @@ async def get_balance(address: str, chain_id: str = "ait-devnet"):
|
||||
|
||||
|
||||
@router.get("/rpc/head", summary="Get current chain head")
|
||||
async def get_head(chain_id: str = "ait-devnet"):
|
||||
async def get_head(chain_id: str = None):
|
||||
"""Get current chain head block"""
|
||||
start = time.perf_counter()
|
||||
|
||||
@@ -799,7 +828,7 @@ async def get_head(chain_id: str = "ait-devnet"):
|
||||
|
||||
|
||||
@router.get("/rpc/transactions", summary="Get latest transactions")
|
||||
async def get_transactions(chain_id: str = "ait-devnet", limit: int = 20, offset: int = 0):
|
||||
async def get_transactions(chain_id: str = None, limit: int = 20, offset: int = 0):
|
||||
"""Get latest transactions"""
|
||||
start = time.perf_counter()
|
||||
|
||||
|
||||
@@ -500,6 +500,6 @@ def create_app() -> FastAPI:
|
||||
|
||||
app = create_app()
|
||||
|
||||
# Register jobs router
|
||||
from .routers import jobs as jobs_router
|
||||
app.include_router(jobs_router.router)
|
||||
# Register jobs router (disabled - legacy)
|
||||
# from .routers import jobs as jobs_router
|
||||
# app.include_router(jobs_router.router)
|
||||
|
||||
@@ -11,11 +11,12 @@ router = APIRouter(tags=["blockchain"])
|
||||
async def blockchain_status():
|
||||
"""Get blockchain status."""
|
||||
try:
|
||||
# Try to get blockchain status from RPC
|
||||
import httpx
|
||||
from ..config import settings
|
||||
|
||||
rpc_url = settings.blockchain_rpc_url.rstrip('/')
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get("http://localhost:8003/rpc/head", timeout=5.0)
|
||||
response = await client.get(f"{rpc_url}/rpc/head", timeout=5.0)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return {
|
||||
@@ -42,11 +43,12 @@ async def blockchain_status():
|
||||
async def blockchain_sync_status():
|
||||
"""Get blockchain synchronization status."""
|
||||
try:
|
||||
# Try to get sync status from RPC
|
||||
import httpx
|
||||
from ..config import settings
|
||||
|
||||
rpc_url = settings.blockchain_rpc_url.rstrip('/')
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get("http://localhost:8003/rpc/sync", timeout=5.0)
|
||||
response = await client.get(f"{rpc_url}/rpc/sync", timeout=5.0)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return {
|
||||
|
||||
@@ -1004,28 +1004,6 @@ def balance(ctx, address, chain_id, all_chains):
|
||||
except Exception as e:
|
||||
error(f"Network error: {e}")
|
||||
|
||||
@blockchain.command()
|
||||
@click.option('--address', required=True, help='Wallet address')
|
||||
@click.option('--amount', type=int, default=1000, help='Amount to mint')
|
||||
@click.pass_context
|
||||
def faucet(ctx, address, amount):
|
||||
"""Mint devnet funds to an address"""
|
||||
config = ctx.obj['config']
|
||||
try:
|
||||
import httpx
|
||||
with httpx.Client() as client:
|
||||
response = client.post(
|
||||
f"{_get_node_endpoint(ctx)}/rpc/admin/mintFaucet",
|
||||
json={"address": address, "amount": amount, "chain_id": "ait-devnet"},
|
||||
timeout=5
|
||||
)
|
||||
if response.status_code in (200, 201):
|
||||
output(response.json(), ctx.obj['output_format'])
|
||||
else:
|
||||
error(f"Failed to use faucet: {response.status_code} - {response.text}")
|
||||
except Exception as e:
|
||||
error(f"Network error: {e}")
|
||||
|
||||
|
||||
@blockchain.command()
|
||||
@click.option('--chain', required=True, help='Chain ID to verify (e.g., ait-mainnet, ait-devnet)')
|
||||
|
||||
@@ -86,7 +86,7 @@ def check_vulnerabilities():
|
||||
"""Run security audits for Python and Node dependencies."""
|
||||
issues = []
|
||||
# Python: pip-audit (if available)
|
||||
rc, out = sh("pip-audit --requirement <(poetry export --without-hashes) 2>&1", shell=True)
|
||||
rc, out = sh("bash -c 'pip-audit --requirement <(poetry export --without-hashes) 2>&1'")
|
||||
if rc == 0:
|
||||
# No vulnerabilities
|
||||
pass
|
||||
|
||||
27
dev/scripts/generate_production_keys.py
Normal file
27
dev/scripts/generate_production_keys.py
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
import secrets
|
||||
import string
|
||||
import json
|
||||
import os
|
||||
|
||||
def random_string(length=32):
|
||||
alphabet = string.ascii_letters + string.digits
|
||||
return ''.join(secrets.choice(alphabet) for _ in range(length))
|
||||
|
||||
def generate_production_keys():
|
||||
client_key = f"client_prod_key_{random_string(24)}"
|
||||
miner_key = f"miner_prod_key_{random_string(24)}"
|
||||
admin_key = f"admin_prod_key_{random_string(24)}"
|
||||
hmac_secret = random_string(64)
|
||||
jwt_secret = random_string(64)
|
||||
return {
|
||||
"CLIENT_API_KEYS": [client_key],
|
||||
"MINER_API_KEYS": [miner_key],
|
||||
"ADMIN_API_KEYS": [admin_key],
|
||||
"HMAC_SECRET": hmac_secret,
|
||||
"JWT_SECRET": jwt_secret
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
keys = generate_production_keys()
|
||||
print(json.dumps(keys, indent=2))
|
||||
44
dev/scripts/security_scan.py
Executable file
44
dev/scripts/security_scan.py
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Security vulnerability scanner for AITBC dependencies.
|
||||
Uses pip-audit to check installed packages in the CLI virtualenv.
|
||||
"""
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
|
||||
PIP_AUDIT = '/opt/aitbc/cli/venv/bin/pip-audit'
|
||||
|
||||
def run_audit():
|
||||
try:
|
||||
result = subprocess.run([PIP_AUDIT, '--format', 'json'],
|
||||
capture_output=True, text=True, timeout=300)
|
||||
if result.returncode not in (0, 1): # 1 means vulns found, 0 means clean
|
||||
return f"❌ pip-audit execution failed (exit {result.returncode}):\n{result.stderr}"
|
||||
data = json.loads(result.stdout) if result.stdout else {}
|
||||
vulns = data.get('vulnerabilities', [])
|
||||
if not vulns:
|
||||
return "✅ Security scan: No known vulnerabilities in installed packages."
|
||||
# Summarize by severity
|
||||
sev_counts = {}
|
||||
for v in vulns:
|
||||
sev = v.get('severity', 'UNKNOWN')
|
||||
sev_counts[sev] = sev_counts.get(sev, 0) + 1
|
||||
lines = ["🚨 Security scan: Found vulnerabilities:"]
|
||||
for sev, count in sorted(sev_counts.items(), key=lambda x: x[1], reverse=True):
|
||||
lines.append(f"- {sev}: {count} package(s)")
|
||||
# Add top 3 vulnerable packages
|
||||
if vulns:
|
||||
lines.append("\nTop vulnerable packages:")
|
||||
for v in vulns[:3]:
|
||||
pkg = v.get('package', 'unknown')
|
||||
vuln_id = v.get('vulnerability_id', 'unknown')
|
||||
lines.append(f"- {pkg}: {vuln_id}")
|
||||
return "\n".join(lines)
|
||||
except Exception as e:
|
||||
return f"❌ Error during security scan: {str(e)}"
|
||||
|
||||
if __name__ == '__main__':
|
||||
message = run_audit()
|
||||
print(message)
|
||||
sys.exit(0)
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
**EXCHANGE INFRASTRUCTURE GAP IDENTIFIED** - While AITBC has achieved complete infrastructure standardization with 19+ services operational, a critical 40% gap exists between documented coin generation concepts and actual implementation. This milestone focuses on implementing missing exchange integration, oracle systems, and market infrastructure to complete the AITBC business model and enable full token economics ecosystem.
|
||||
|
||||
Comprehensive analysis reveals that core wallet operations (60% complete) are fully functional, but critical exchange integration components (40% missing) are essential for the complete AITBC business model. The platform requires immediate implementation of exchange commands, oracle systems, market making infrastructure, and advanced security features to achieve the documented vision.
|
||||
Comprehensive analysis confirms core wallet operations are fully functional and exchange integration components are now in place. Focus shifts to sustaining reliability (exchange commands, oracle systems, market making) and hardening security to keep the ecosystem production-ready.
|
||||
|
||||
## Current Status Analysis
|
||||
|
||||
|
||||
140
infra/helm/values/prod.yaml
Normal file
140
infra/helm/values/prod.yaml
Normal 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"
|
||||
259
infra/helm/values/prod/values.yaml
Normal file
259
infra/helm/values/prod/values.yaml
Normal 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
|
||||
247
infra/nginx/nginx-aitbc-reverse-proxy.conf
Normal file
247
infra/nginx/nginx-aitbc-reverse-proxy.conf
Normal 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;
|
||||
}
|
||||
}
|
||||
133
infra/nginx/nginx-aitbc.conf
Normal file
133
infra/nginx/nginx-aitbc.conf
Normal 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";
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
>;
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
>;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type { AccessControl } from "./AccessControl";
|
||||
export type { IAccessControl } from "./IAccessControl";
|
||||
@@ -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 };
|
||||
@@ -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: {};
|
||||
}
|
||||
@@ -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: {};
|
||||
}
|
||||
@@ -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: {};
|
||||
}
|
||||
@@ -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";
|
||||
@@ -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 };
|
||||
@@ -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
|
||||
>;
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
>;
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
>;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type { IERC20Metadata } from "./IERC20Metadata";
|
||||
@@ -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";
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type * as erc20 from "./ERC20";
|
||||
export type { erc20 };
|
||||
@@ -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: {};
|
||||
}
|
||||
@@ -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: {};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type { ECDSA } from "./ECDSA";
|
||||
@@ -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";
|
||||
@@ -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: {};
|
||||
}
|
||||
@@ -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: {};
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type { ERC165 } from "./ERC165";
|
||||
export type { IERC165 } from "./IERC165";
|
||||
@@ -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: {};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type { SafeCast } from "./SafeCast";
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type * as contracts from "./contracts";
|
||||
export type { contracts };
|
||||
131
packages/solidity/aitbc-token/typechain-types/common.ts
Normal file
131
packages/solidity/aitbc-token/typechain-types/common.ts
Normal 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>;
|
||||
}
|
||||
@@ -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
|
||||
>;
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
>;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type { AIToken } from "./AIToken";
|
||||
export type { AITokenRegistry } from "./AITokenRegistry";
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
@@ -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";
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Contract, Interface, type ContractRunner } from "ethers";
|
||||
import type {
|
||||
IERC20Errors,
|
||||
IERC20ErrorsInterface,
|
||||
} from "../../../../../@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "allowance",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "needed",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "ERC20InsufficientAllowance",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "sender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "balance",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "needed",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "ERC20InsufficientBalance",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "approver",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC20InvalidApprover",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "receiver",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC20InvalidReceiver",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "sender",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC20InvalidSender",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC20InvalidSpender",
|
||||
type: "error",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export class IERC20Errors__factory {
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): IERC20ErrorsInterface {
|
||||
return new Interface(_abi) as IERC20ErrorsInterface;
|
||||
}
|
||||
static connect(
|
||||
address: string,
|
||||
runner?: ContractRunner | null
|
||||
): IERC20Errors {
|
||||
return new Contract(address, _abi, runner) as unknown as IERC20Errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Contract, Interface, type ContractRunner } from "ethers";
|
||||
import type {
|
||||
IERC721Errors,
|
||||
IERC721ErrorsInterface,
|
||||
} from "../../../../../@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "sender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "tokenId",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC721IncorrectOwner",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "operator",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "tokenId",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "ERC721InsufficientApproval",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "approver",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC721InvalidApprover",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "operator",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC721InvalidOperator",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC721InvalidOwner",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "receiver",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC721InvalidReceiver",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "sender",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC721InvalidSender",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "tokenId",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "ERC721NonexistentToken",
|
||||
type: "error",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export class IERC721Errors__factory {
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): IERC721ErrorsInterface {
|
||||
return new Interface(_abi) as IERC721ErrorsInterface;
|
||||
}
|
||||
static connect(
|
||||
address: string,
|
||||
runner?: ContractRunner | null
|
||||
): IERC721Errors {
|
||||
return new Contract(address, _abi, runner) as unknown as IERC721Errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export { IERC1155Errors__factory } from "./IERC1155Errors__factory";
|
||||
export { IERC20Errors__factory } from "./IERC20Errors__factory";
|
||||
export { IERC721Errors__factory } from "./IERC721Errors__factory";
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as draftIerc6093Sol from "./draft-IERC6093.sol";
|
||||
@@ -0,0 +1,330 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Contract, Interface, type ContractRunner } from "ethers";
|
||||
import type {
|
||||
ERC20,
|
||||
ERC20Interface,
|
||||
} from "../../../../../@openzeppelin/contracts/token/ERC20/ERC20";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "allowance",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "needed",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "ERC20InsufficientAllowance",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "sender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "balance",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "needed",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "ERC20InsufficientBalance",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "approver",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC20InvalidApprover",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "receiver",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC20InvalidReceiver",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "sender",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC20InvalidSender",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "ERC20InvalidSpender",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "Approval",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "from",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "Transfer",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "allowance",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "approve",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "balanceOf",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "decimals",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint8",
|
||||
name: "",
|
||||
type: "uint8",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "name",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "string",
|
||||
name: "",
|
||||
type: "string",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "symbol",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "string",
|
||||
name: "",
|
||||
type: "string",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "totalSupply",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "transfer",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "from",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "transferFrom",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export class ERC20__factory {
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): ERC20Interface {
|
||||
return new Interface(_abi) as ERC20Interface;
|
||||
}
|
||||
static connect(address: string, runner?: ContractRunner | null): ERC20 {
|
||||
return new Contract(address, _abi, runner) as unknown as ERC20;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Contract, Interface, type ContractRunner } from "ethers";
|
||||
import type {
|
||||
IERC20,
|
||||
IERC20Interface,
|
||||
} from "../../../../../@openzeppelin/contracts/token/ERC20/IERC20";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "Approval",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "from",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "Transfer",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "allowance",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "approve",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "balanceOf",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "totalSupply",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "transfer",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "from",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "transferFrom",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export class IERC20__factory {
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): IERC20Interface {
|
||||
return new Interface(_abi) as IERC20Interface;
|
||||
}
|
||||
static connect(address: string, runner?: ContractRunner | null): IERC20 {
|
||||
return new Contract(address, _abi, runner) as unknown as IERC20;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Contract, Interface, type ContractRunner } from "ethers";
|
||||
import type {
|
||||
IERC20Metadata,
|
||||
IERC20MetadataInterface,
|
||||
} from "../../../../../../@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "Approval",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "from",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "Transfer",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "allowance",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "approve",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "balanceOf",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "decimals",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint8",
|
||||
name: "",
|
||||
type: "uint8",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "name",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "string",
|
||||
name: "",
|
||||
type: "string",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "symbol",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "string",
|
||||
name: "",
|
||||
type: "string",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "totalSupply",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "transfer",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "from",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "transferFrom",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export class IERC20Metadata__factory {
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): IERC20MetadataInterface {
|
||||
return new Interface(_abi) as IERC20MetadataInterface;
|
||||
}
|
||||
static connect(
|
||||
address: string,
|
||||
runner?: ContractRunner | null
|
||||
): IERC20Metadata {
|
||||
return new Contract(address, _abi, runner) as unknown as IERC20Metadata;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export { IERC20Metadata__factory } from "./IERC20Metadata__factory";
|
||||
@@ -0,0 +1,6 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as extensions from "./extensions";
|
||||
export { ERC20__factory } from "./ERC20__factory";
|
||||
export { IERC20__factory } from "./IERC20__factory";
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as erc20 from "./ERC20";
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import {
|
||||
Contract,
|
||||
ContractFactory,
|
||||
ContractTransactionResponse,
|
||||
Interface,
|
||||
} from "ethers";
|
||||
import type { Signer, ContractDeployTransaction, ContractRunner } from "ethers";
|
||||
import type { NonPayableOverrides } from "../../../../common";
|
||||
import type {
|
||||
Strings,
|
||||
StringsInterface,
|
||||
} from "../../../../@openzeppelin/contracts/utils/Strings";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "length",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "StringsInsufficientHexLength",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "StringsInvalidAddressFormat",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "StringsInvalidChar",
|
||||
type: "error",
|
||||
},
|
||||
] as const;
|
||||
|
||||
const _bytecode =
|
||||
"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d3fa6b95cf4f76e64227a9b2373ccb228efd9715fd7983e0646867999cceb9fb64736f6c63430008180033";
|
||||
|
||||
type StringsConstructorParams =
|
||||
| [signer?: Signer]
|
||||
| ConstructorParameters<typeof ContractFactory>;
|
||||
|
||||
const isSuperArgs = (
|
||||
xs: StringsConstructorParams
|
||||
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;
|
||||
|
||||
export class Strings__factory extends ContractFactory {
|
||||
constructor(...args: StringsConstructorParams) {
|
||||
if (isSuperArgs(args)) {
|
||||
super(...args);
|
||||
} else {
|
||||
super(_abi, _bytecode, args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
override getDeployTransaction(
|
||||
overrides?: NonPayableOverrides & { from?: string }
|
||||
): Promise<ContractDeployTransaction> {
|
||||
return super.getDeployTransaction(overrides || {});
|
||||
}
|
||||
override deploy(overrides?: NonPayableOverrides & { from?: string }) {
|
||||
return super.deploy(overrides || {}) as Promise<
|
||||
Strings & {
|
||||
deploymentTransaction(): ContractTransactionResponse;
|
||||
}
|
||||
>;
|
||||
}
|
||||
override connect(runner: ContractRunner | null): Strings__factory {
|
||||
return super.connect(runner) as Strings__factory;
|
||||
}
|
||||
|
||||
static readonly bytecode = _bytecode;
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): StringsInterface {
|
||||
return new Interface(_abi) as StringsInterface;
|
||||
}
|
||||
static connect(address: string, runner?: ContractRunner | null): Strings {
|
||||
return new Contract(address, _abi, runner) as unknown as Strings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import {
|
||||
Contract,
|
||||
ContractFactory,
|
||||
ContractTransactionResponse,
|
||||
Interface,
|
||||
} from "ethers";
|
||||
import type { Signer, ContractDeployTransaction, ContractRunner } from "ethers";
|
||||
import type { NonPayableOverrides } from "../../../../../common";
|
||||
import type {
|
||||
ECDSA,
|
||||
ECDSAInterface,
|
||||
} from "../../../../../@openzeppelin/contracts/utils/cryptography/ECDSA";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [],
|
||||
name: "ECDSAInvalidSignature",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "length",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "ECDSAInvalidSignatureLength",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "s",
|
||||
type: "bytes32",
|
||||
},
|
||||
],
|
||||
name: "ECDSAInvalidSignatureS",
|
||||
type: "error",
|
||||
},
|
||||
] as const;
|
||||
|
||||
const _bytecode =
|
||||
"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220a02ae933cd95f2ee943a9a3e5cbf4c6b7a6f7cc463d2cb58fac8fce23a0ba09464736f6c63430008180033";
|
||||
|
||||
type ECDSAConstructorParams =
|
||||
| [signer?: Signer]
|
||||
| ConstructorParameters<typeof ContractFactory>;
|
||||
|
||||
const isSuperArgs = (
|
||||
xs: ECDSAConstructorParams
|
||||
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;
|
||||
|
||||
export class ECDSA__factory extends ContractFactory {
|
||||
constructor(...args: ECDSAConstructorParams) {
|
||||
if (isSuperArgs(args)) {
|
||||
super(...args);
|
||||
} else {
|
||||
super(_abi, _bytecode, args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
override getDeployTransaction(
|
||||
overrides?: NonPayableOverrides & { from?: string }
|
||||
): Promise<ContractDeployTransaction> {
|
||||
return super.getDeployTransaction(overrides || {});
|
||||
}
|
||||
override deploy(overrides?: NonPayableOverrides & { from?: string }) {
|
||||
return super.deploy(overrides || {}) as Promise<
|
||||
ECDSA & {
|
||||
deploymentTransaction(): ContractTransactionResponse;
|
||||
}
|
||||
>;
|
||||
}
|
||||
override connect(runner: ContractRunner | null): ECDSA__factory {
|
||||
return super.connect(runner) as ECDSA__factory;
|
||||
}
|
||||
|
||||
static readonly bytecode = _bytecode;
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): ECDSAInterface {
|
||||
return new Interface(_abi) as ECDSAInterface;
|
||||
}
|
||||
static connect(address: string, runner?: ContractRunner | null): ECDSA {
|
||||
return new Contract(address, _abi, runner) as unknown as ECDSA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export { ECDSA__factory } from "./ECDSA__factory";
|
||||
@@ -0,0 +1,7 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as cryptography from "./cryptography";
|
||||
export * as introspection from "./introspection";
|
||||
export * as math from "./math";
|
||||
export { Strings__factory } from "./Strings__factory";
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Contract, Interface, type ContractRunner } from "ethers";
|
||||
import type {
|
||||
ERC165,
|
||||
ERC165Interface,
|
||||
} from "../../../../../@openzeppelin/contracts/utils/introspection/ERC165";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes4",
|
||||
name: "interfaceId",
|
||||
type: "bytes4",
|
||||
},
|
||||
],
|
||||
name: "supportsInterface",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export class ERC165__factory {
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): ERC165Interface {
|
||||
return new Interface(_abi) as ERC165Interface;
|
||||
}
|
||||
static connect(address: string, runner?: ContractRunner | null): ERC165 {
|
||||
return new Contract(address, _abi, runner) as unknown as ERC165;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Contract, Interface, type ContractRunner } from "ethers";
|
||||
import type {
|
||||
IERC165,
|
||||
IERC165Interface,
|
||||
} from "../../../../../@openzeppelin/contracts/utils/introspection/IERC165";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes4",
|
||||
name: "interfaceId",
|
||||
type: "bytes4",
|
||||
},
|
||||
],
|
||||
name: "supportsInterface",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export class IERC165__factory {
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): IERC165Interface {
|
||||
return new Interface(_abi) as IERC165Interface;
|
||||
}
|
||||
static connect(address: string, runner?: ContractRunner | null): IERC165 {
|
||||
return new Contract(address, _abi, runner) as unknown as IERC165;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export { ERC165__factory } from "./ERC165__factory";
|
||||
export { IERC165__factory } from "./IERC165__factory";
|
||||
@@ -0,0 +1,118 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import {
|
||||
Contract,
|
||||
ContractFactory,
|
||||
ContractTransactionResponse,
|
||||
Interface,
|
||||
} from "ethers";
|
||||
import type { Signer, ContractDeployTransaction, ContractRunner } from "ethers";
|
||||
import type { NonPayableOverrides } from "../../../../../common";
|
||||
import type {
|
||||
SafeCast,
|
||||
SafeCastInterface,
|
||||
} from "../../../../../@openzeppelin/contracts/utils/math/SafeCast";
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint8",
|
||||
name: "bits",
|
||||
type: "uint8",
|
||||
},
|
||||
{
|
||||
internalType: "int256",
|
||||
name: "value",
|
||||
type: "int256",
|
||||
},
|
||||
],
|
||||
name: "SafeCastOverflowedIntDowncast",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "int256",
|
||||
name: "value",
|
||||
type: "int256",
|
||||
},
|
||||
],
|
||||
name: "SafeCastOverflowedIntToUint",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint8",
|
||||
name: "bits",
|
||||
type: "uint8",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "SafeCastOverflowedUintDowncast",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "SafeCastOverflowedUintToInt",
|
||||
type: "error",
|
||||
},
|
||||
] as const;
|
||||
|
||||
const _bytecode =
|
||||
"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212201c97bba8d553a67561101942b2a9afa3628667de55efed8df898d3aab783793c64736f6c63430008180033";
|
||||
|
||||
type SafeCastConstructorParams =
|
||||
| [signer?: Signer]
|
||||
| ConstructorParameters<typeof ContractFactory>;
|
||||
|
||||
const isSuperArgs = (
|
||||
xs: SafeCastConstructorParams
|
||||
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;
|
||||
|
||||
export class SafeCast__factory extends ContractFactory {
|
||||
constructor(...args: SafeCastConstructorParams) {
|
||||
if (isSuperArgs(args)) {
|
||||
super(...args);
|
||||
} else {
|
||||
super(_abi, _bytecode, args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
override getDeployTransaction(
|
||||
overrides?: NonPayableOverrides & { from?: string }
|
||||
): Promise<ContractDeployTransaction> {
|
||||
return super.getDeployTransaction(overrides || {});
|
||||
}
|
||||
override deploy(overrides?: NonPayableOverrides & { from?: string }) {
|
||||
return super.deploy(overrides || {}) as Promise<
|
||||
SafeCast & {
|
||||
deploymentTransaction(): ContractTransactionResponse;
|
||||
}
|
||||
>;
|
||||
}
|
||||
override connect(runner: ContractRunner | null): SafeCast__factory {
|
||||
return super.connect(runner) as SafeCast__factory;
|
||||
}
|
||||
|
||||
static readonly bytecode = _bytecode;
|
||||
static readonly abi = _abi;
|
||||
static createInterface(): SafeCastInterface {
|
||||
return new Interface(_abi) as SafeCastInterface;
|
||||
}
|
||||
static connect(address: string, runner?: ContractRunner | null): SafeCast {
|
||||
return new Contract(address, _abi, runner) as unknown as SafeCast;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export { SafeCast__factory } from "./SafeCast__factory";
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as contracts from "./contracts";
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export { AIToken__factory } from "./AIToken__factory";
|
||||
export { AITokenRegistry__factory } from "./AITokenRegistry__factory";
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as openzeppelin from "./@openzeppelin";
|
||||
export * as contracts from "./contracts";
|
||||
315
packages/solidity/aitbc-token/typechain-types/hardhat.d.ts
vendored
Normal file
315
packages/solidity/aitbc-token/typechain-types/hardhat.d.ts
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { ethers } from "ethers";
|
||||
import {
|
||||
DeployContractOptions,
|
||||
FactoryOptions,
|
||||
HardhatEthersHelpers as HardhatEthersHelpersBase,
|
||||
} from "@nomicfoundation/hardhat-ethers/types";
|
||||
|
||||
import * as Contracts from ".";
|
||||
|
||||
declare module "hardhat/types/runtime" {
|
||||
interface HardhatEthersHelpers extends HardhatEthersHelpersBase {
|
||||
getContractFactory(
|
||||
name: "AccessControl",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.AccessControl__factory>;
|
||||
getContractFactory(
|
||||
name: "IAccessControl",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.IAccessControl__factory>;
|
||||
getContractFactory(
|
||||
name: "IERC1155Errors",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.IERC1155Errors__factory>;
|
||||
getContractFactory(
|
||||
name: "IERC20Errors",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.IERC20Errors__factory>;
|
||||
getContractFactory(
|
||||
name: "IERC721Errors",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.IERC721Errors__factory>;
|
||||
getContractFactory(
|
||||
name: "ERC20",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.ERC20__factory>;
|
||||
getContractFactory(
|
||||
name: "IERC20Metadata",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.IERC20Metadata__factory>;
|
||||
getContractFactory(
|
||||
name: "IERC20",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.IERC20__factory>;
|
||||
getContractFactory(
|
||||
name: "ECDSA",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.ECDSA__factory>;
|
||||
getContractFactory(
|
||||
name: "ERC165",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.ERC165__factory>;
|
||||
getContractFactory(
|
||||
name: "IERC165",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.IERC165__factory>;
|
||||
getContractFactory(
|
||||
name: "SafeCast",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.SafeCast__factory>;
|
||||
getContractFactory(
|
||||
name: "Strings",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.Strings__factory>;
|
||||
getContractFactory(
|
||||
name: "AIToken",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.AIToken__factory>;
|
||||
getContractFactory(
|
||||
name: "AITokenRegistry",
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<Contracts.AITokenRegistry__factory>;
|
||||
|
||||
getContractAt(
|
||||
name: "AccessControl",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.AccessControl>;
|
||||
getContractAt(
|
||||
name: "IAccessControl",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.IAccessControl>;
|
||||
getContractAt(
|
||||
name: "IERC1155Errors",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.IERC1155Errors>;
|
||||
getContractAt(
|
||||
name: "IERC20Errors",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.IERC20Errors>;
|
||||
getContractAt(
|
||||
name: "IERC721Errors",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.IERC721Errors>;
|
||||
getContractAt(
|
||||
name: "ERC20",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.ERC20>;
|
||||
getContractAt(
|
||||
name: "IERC20Metadata",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.IERC20Metadata>;
|
||||
getContractAt(
|
||||
name: "IERC20",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.IERC20>;
|
||||
getContractAt(
|
||||
name: "ECDSA",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.ECDSA>;
|
||||
getContractAt(
|
||||
name: "ERC165",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.ERC165>;
|
||||
getContractAt(
|
||||
name: "IERC165",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.IERC165>;
|
||||
getContractAt(
|
||||
name: "SafeCast",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.SafeCast>;
|
||||
getContractAt(
|
||||
name: "Strings",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.Strings>;
|
||||
getContractAt(
|
||||
name: "AIToken",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.AIToken>;
|
||||
getContractAt(
|
||||
name: "AITokenRegistry",
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<Contracts.AITokenRegistry>;
|
||||
|
||||
deployContract(
|
||||
name: "AccessControl",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.AccessControl>;
|
||||
deployContract(
|
||||
name: "IAccessControl",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IAccessControl>;
|
||||
deployContract(
|
||||
name: "IERC1155Errors",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC1155Errors>;
|
||||
deployContract(
|
||||
name: "IERC20Errors",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC20Errors>;
|
||||
deployContract(
|
||||
name: "IERC721Errors",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC721Errors>;
|
||||
deployContract(
|
||||
name: "ERC20",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.ERC20>;
|
||||
deployContract(
|
||||
name: "IERC20Metadata",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC20Metadata>;
|
||||
deployContract(
|
||||
name: "IERC20",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC20>;
|
||||
deployContract(
|
||||
name: "ECDSA",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.ECDSA>;
|
||||
deployContract(
|
||||
name: "ERC165",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.ERC165>;
|
||||
deployContract(
|
||||
name: "IERC165",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC165>;
|
||||
deployContract(
|
||||
name: "SafeCast",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.SafeCast>;
|
||||
deployContract(
|
||||
name: "Strings",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.Strings>;
|
||||
deployContract(
|
||||
name: "AIToken",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.AIToken>;
|
||||
deployContract(
|
||||
name: "AITokenRegistry",
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.AITokenRegistry>;
|
||||
|
||||
deployContract(
|
||||
name: "AccessControl",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.AccessControl>;
|
||||
deployContract(
|
||||
name: "IAccessControl",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IAccessControl>;
|
||||
deployContract(
|
||||
name: "IERC1155Errors",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC1155Errors>;
|
||||
deployContract(
|
||||
name: "IERC20Errors",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC20Errors>;
|
||||
deployContract(
|
||||
name: "IERC721Errors",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC721Errors>;
|
||||
deployContract(
|
||||
name: "ERC20",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.ERC20>;
|
||||
deployContract(
|
||||
name: "IERC20Metadata",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC20Metadata>;
|
||||
deployContract(
|
||||
name: "IERC20",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC20>;
|
||||
deployContract(
|
||||
name: "ECDSA",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.ECDSA>;
|
||||
deployContract(
|
||||
name: "ERC165",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.ERC165>;
|
||||
deployContract(
|
||||
name: "IERC165",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.IERC165>;
|
||||
deployContract(
|
||||
name: "SafeCast",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.SafeCast>;
|
||||
deployContract(
|
||||
name: "Strings",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.Strings>;
|
||||
deployContract(
|
||||
name: "AIToken",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.AIToken>;
|
||||
deployContract(
|
||||
name: "AITokenRegistry",
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<Contracts.AITokenRegistry>;
|
||||
|
||||
// default types
|
||||
getContractFactory(
|
||||
name: string,
|
||||
signerOrOptions?: ethers.Signer | FactoryOptions
|
||||
): Promise<ethers.ContractFactory>;
|
||||
getContractFactory(
|
||||
abi: any[],
|
||||
bytecode: ethers.BytesLike,
|
||||
signer?: ethers.Signer
|
||||
): Promise<ethers.ContractFactory>;
|
||||
getContractAt(
|
||||
nameOrAbi: string | any[],
|
||||
address: string | ethers.Addressable,
|
||||
signer?: ethers.Signer
|
||||
): Promise<ethers.Contract>;
|
||||
deployContract(
|
||||
name: string,
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<ethers.Contract>;
|
||||
deployContract(
|
||||
name: string,
|
||||
args: any[],
|
||||
signerOrOptions?: ethers.Signer | DeployContractOptions
|
||||
): Promise<ethers.Contract>;
|
||||
}
|
||||
}
|
||||
38
packages/solidity/aitbc-token/typechain-types/index.ts
Normal file
38
packages/solidity/aitbc-token/typechain-types/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type * as openzeppelin from "./@openzeppelin";
|
||||
export type { openzeppelin };
|
||||
import type * as contracts from "./contracts";
|
||||
export type { contracts };
|
||||
export * as factories from "./factories";
|
||||
export type { AccessControl } from "./@openzeppelin/contracts/access/AccessControl";
|
||||
export { AccessControl__factory } from "./factories/@openzeppelin/contracts/access/AccessControl__factory";
|
||||
export type { IAccessControl } from "./@openzeppelin/contracts/access/IAccessControl";
|
||||
export { IAccessControl__factory } from "./factories/@openzeppelin/contracts/access/IAccessControl__factory";
|
||||
export type { IERC1155Errors } from "./@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors";
|
||||
export { IERC1155Errors__factory } from "./factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors__factory";
|
||||
export type { IERC20Errors } from "./@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors";
|
||||
export { IERC20Errors__factory } from "./factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors__factory";
|
||||
export type { IERC721Errors } from "./@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors";
|
||||
export { IERC721Errors__factory } from "./factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors__factory";
|
||||
export type { ERC20 } from "./@openzeppelin/contracts/token/ERC20/ERC20";
|
||||
export { ERC20__factory } from "./factories/@openzeppelin/contracts/token/ERC20/ERC20__factory";
|
||||
export type { IERC20Metadata } from "./@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata";
|
||||
export { IERC20Metadata__factory } from "./factories/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata__factory";
|
||||
export type { IERC20 } from "./@openzeppelin/contracts/token/ERC20/IERC20";
|
||||
export { IERC20__factory } from "./factories/@openzeppelin/contracts/token/ERC20/IERC20__factory";
|
||||
export type { ECDSA } from "./@openzeppelin/contracts/utils/cryptography/ECDSA";
|
||||
export { ECDSA__factory } from "./factories/@openzeppelin/contracts/utils/cryptography/ECDSA__factory";
|
||||
export type { ERC165 } from "./@openzeppelin/contracts/utils/introspection/ERC165";
|
||||
export { ERC165__factory } from "./factories/@openzeppelin/contracts/utils/introspection/ERC165__factory";
|
||||
export type { IERC165 } from "./@openzeppelin/contracts/utils/introspection/IERC165";
|
||||
export { IERC165__factory } from "./factories/@openzeppelin/contracts/utils/introspection/IERC165__factory";
|
||||
export type { SafeCast } from "./@openzeppelin/contracts/utils/math/SafeCast";
|
||||
export { SafeCast__factory } from "./factories/@openzeppelin/contracts/utils/math/SafeCast__factory";
|
||||
export type { Strings } from "./@openzeppelin/contracts/utils/Strings";
|
||||
export { Strings__factory } from "./factories/@openzeppelin/contracts/utils/Strings__factory";
|
||||
export type { AIToken } from "./contracts/AIToken";
|
||||
export { AIToken__factory } from "./factories/contracts/AIToken__factory";
|
||||
export type { AITokenRegistry } from "./contracts/AITokenRegistry";
|
||||
export { AITokenRegistry__factory } from "./factories/contracts/AITokenRegistry__factory";
|
||||
24
scripts/deploy/cleanup-deployment.sh
Executable file
24
scripts/deploy/cleanup-deployment.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Clean up failed deployment and prepare for redeployment
|
||||
|
||||
echo "🧹 Cleaning up failed deployment..."
|
||||
echo "=================================="
|
||||
|
||||
# Stop any running services
|
||||
echo "Stopping services..."
|
||||
ssh ns3-root "systemctl stop blockchain-node blockchain-rpc nginx 2>/dev/null || true"
|
||||
|
||||
# Remove old directories
|
||||
echo "Removing old directories..."
|
||||
ssh ns3-root "rm -rf /opt/blockchain-node /opt/blockchain-node-src /opt/blockchain-explorer 2>/dev/null || true"
|
||||
|
||||
# Remove systemd services
|
||||
echo "Removing systemd services..."
|
||||
ssh ns3-root "systemctl disable blockchain-node blockchain-rpc blockchain-explorer 2>/dev/null || true"
|
||||
ssh ns3-root "rm -f /etc/systemd/system/blockchain-node.service /etc/systemd/system/blockchain-rpc.service /etc/systemd/system/blockchain-explorer.service 2>/dev/null || true"
|
||||
ssh ns3-root "systemctl daemon-reload"
|
||||
|
||||
echo "✅ Cleanup complete!"
|
||||
echo ""
|
||||
echo "You can now run: ./scripts/deploy/deploy-all-remote.sh"
|
||||
109
scripts/deploy/container-deploy.py
Normal file
109
scripts/deploy/container-deploy.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Deploy AITBC services to incus container
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
|
||||
def run_command(cmd, container=None):
|
||||
"""Run command locally or in container"""
|
||||
if container:
|
||||
cmd = f"incus exec {container} -- {cmd}"
|
||||
print(f"Running: {cmd}")
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"Error: {result.stderr}")
|
||||
return False
|
||||
return True
|
||||
|
||||
def deploy_to_container():
|
||||
container = "aitbc"
|
||||
container_ip = "10.1.223.93"
|
||||
|
||||
print("🚀 Deploying AITBC services to container...")
|
||||
|
||||
# Stop local services
|
||||
print("\n📋 Stopping local services...")
|
||||
subprocess.run("sudo fuser -k 8000/tcp 2>/dev/null || true", shell=True)
|
||||
subprocess.run("sudo fuser -k 9080/tcp 2>/dev/null || true", shell=True)
|
||||
subprocess.run("pkill -f 'marketplace-ui' 2>/dev/null || true", shell=True)
|
||||
subprocess.run("pkill -f 'trade-exchange' 2>/dev/null || true", shell=True)
|
||||
|
||||
# Copy project to container
|
||||
print("\n📁 Copying project to container...")
|
||||
subprocess.run(f"incus file push -r /home/oib/windsurf/aitbc {container}/home/oib/", shell=True)
|
||||
|
||||
# Setup Python environment in container
|
||||
print("\n🐍 Setting up Python environment...")
|
||||
run_command("cd /home/oib/aitbc && python3 -m venv .venv", container)
|
||||
run_command("cd /home/oib/aitbc && source .venv/bin/activate && pip install fastapi uvicorn httpx sqlmodel", container)
|
||||
|
||||
# Install dependencies
|
||||
print("\n📦 Installing dependencies...")
|
||||
run_command("cd /home/oib/aitbc/apps/coordinator-api && source ../../.venv/bin/activate && pip install -e .", container)
|
||||
run_command("cd /home/oib/aitbc/apps/blockchain-node && source ../../.venv/bin/activate && pip install -e .", container)
|
||||
|
||||
# Create startup script
|
||||
print("\n🔧 Creating startup script...")
|
||||
startup_script = """#!/bin/bash
|
||||
cd /home/oib/aitbc
|
||||
|
||||
# Start blockchain node
|
||||
echo "Starting blockchain node..."
|
||||
cd apps/blockchain-node
|
||||
source ../../.venv/bin/activate
|
||||
python -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 9080 &
|
||||
NODE_PID=$!
|
||||
|
||||
# Start coordinator API
|
||||
echo "Starting coordinator API..."
|
||||
cd ../coordinator-api
|
||||
source ../../.venv/bin/activate
|
||||
python -m uvicorn src.app.main:app --host 0.0.0.0 --port 8000 &
|
||||
COORD_PID=$!
|
||||
|
||||
# Start marketplace UI
|
||||
echo "Starting marketplace UI..."
|
||||
cd ../marketplace-ui
|
||||
python server.py --port 3001 &
|
||||
MARKET_PID=$!
|
||||
|
||||
# Start trade exchange
|
||||
echo "Starting trade exchange..."
|
||||
cd ../trade-exchange
|
||||
python server.py --port 3002 &
|
||||
EXCHANGE_PID=$!
|
||||
|
||||
echo "Services started!"
|
||||
echo "Blockchain: http://10.1.223.93:9080"
|
||||
echo "API: http://10.1.223.93:8000"
|
||||
echo "Marketplace: http://10.1.223.93:3001"
|
||||
echo "Exchange: http://10.1.223.93:3002"
|
||||
|
||||
# Wait for services
|
||||
wait $NODE_PID $COORD_PID $MARKET_PID $EXCHANGE_PID
|
||||
"""
|
||||
|
||||
# Write startup script to container
|
||||
with open('/tmp/start_aitbc.sh', 'w') as f:
|
||||
f.write(startup_script)
|
||||
|
||||
subprocess.run("incus file push /tmp/start_aitbc.sh aitbc/home/oib/", shell=True)
|
||||
run_command("chmod +x /home/oib/start_aitbc.sh", container)
|
||||
|
||||
# Start services
|
||||
print("\n🚀 Starting AITBC services...")
|
||||
run_command("/home/oib/start_aitbc.sh", container)
|
||||
|
||||
print(f"\n✅ Services deployed to container!")
|
||||
print(f"\n📋 Access URLs:")
|
||||
print(f" 🌐 Container IP: {container_ip}")
|
||||
print(f" 📊 Marketplace: http://{container_ip}:3001")
|
||||
print(f" 💱 Trade Exchange: http://{container_ip}:3002")
|
||||
print(f" 🔗 API: http://{container_ip}:8000")
|
||||
print(f" ⛓️ Blockchain: http://{container_ip}:9080")
|
||||
|
||||
if __name__ == "__main__":
|
||||
deploy_to_container()
|
||||
56
scripts/deploy/deploy-all-remote.sh
Executable file
56
scripts/deploy/deploy-all-remote.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy blockchain node and explorer by building directly on ns3
|
||||
|
||||
echo "🚀 AITBC Remote Deployment (Build on Server)"
|
||||
echo "=========================================="
|
||||
echo "This will build the blockchain node directly on ns3"
|
||||
echo "to utilize the gigabit connection instead of uploading."
|
||||
echo ""
|
||||
|
||||
# Copy deployment scripts to server
|
||||
echo "Copying deployment scripts to ns3..."
|
||||
scp scripts/deploy/deploy-blockchain-remote.sh ns3-root:/opt/
|
||||
scp scripts/deploy/deploy-explorer-remote.sh ns3-root:/opt/
|
||||
|
||||
# Create directories on server first
|
||||
echo "Creating directories on ns3..."
|
||||
ssh ns3-root "mkdir -p /opt/blockchain-node-src /opt/blockchain-node"
|
||||
|
||||
# Copy blockchain source code to server (excluding data files)
|
||||
echo "Copying blockchain source code to ns3..."
|
||||
rsync -av --exclude='data/' --exclude='*.db' --exclude='__pycache__' --exclude='.venv' apps/blockchain-node/ ns3-root:/opt/blockchain-node-src/
|
||||
|
||||
# Execute blockchain deployment
|
||||
echo ""
|
||||
echo "Deploying blockchain node..."
|
||||
ssh ns3-root "cd /opt && cp -r /opt/blockchain-node-src/* /opt/blockchain-node/ && cd /opt/blockchain-node && chmod +x ../deploy-blockchain-remote.sh && ../deploy-blockchain-remote.sh"
|
||||
|
||||
# Wait for blockchain to start
|
||||
echo ""
|
||||
echo "Waiting 10 seconds for blockchain node to start..."
|
||||
sleep 10
|
||||
|
||||
# Execute explorer deployment on ns3
|
||||
echo ""
|
||||
echo "Deploying blockchain explorer..."
|
||||
ssh ns3-root "cd /opt && ./deploy-explorer-remote.sh"
|
||||
|
||||
# Check services
|
||||
echo ""
|
||||
echo "Checking service status..."
|
||||
ssh ns3-root "systemctl status blockchain-node blockchain-rpc nginx --no-pager | grep -E 'Active:|Main PID:'"
|
||||
|
||||
echo ""
|
||||
echo "✅ Deployment complete!"
|
||||
echo ""
|
||||
echo "Services:"
|
||||
echo " - Blockchain Node RPC: http://localhost:8082"
|
||||
echo " - Blockchain Explorer: http://localhost:3000"
|
||||
echo ""
|
||||
echo "External access:"
|
||||
echo " - Blockchain Node RPC: http://aitbc.keisanki.net:8082"
|
||||
echo " - Blockchain Explorer: http://aitbc.keisanki.net:3000"
|
||||
echo ""
|
||||
echo "The blockchain node will start syncing automatically."
|
||||
echo "The explorer connects to the local node and displays real-time data."
|
||||
207
scripts/deploy/deploy-blockchain-and-explorer.sh
Executable file
207
scripts/deploy/deploy-blockchain-and-explorer.sh
Executable file
@@ -0,0 +1,207 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy blockchain node and explorer to incus container
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Deploying Blockchain Node and Explorer"
|
||||
echo "========================================"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Copy blockchain node to container
|
||||
print_status "Copying blockchain node to container..."
|
||||
ssh ns3-root "rm -rf /opt/blockchain-node 2>/dev/null || true"
|
||||
scp -r apps/blockchain-node ns3-root:/opt/
|
||||
|
||||
# Setup blockchain node in container
|
||||
print_status "Setting up blockchain node..."
|
||||
ssh ns3-root << 'EOF'
|
||||
cd /opt/blockchain-node
|
||||
|
||||
# Create configuration
|
||||
cat > .env << EOL
|
||||
CHAIN_ID=ait-devnet
|
||||
DB_PATH=./data/chain.db
|
||||
RPC_BIND_HOST=0.0.0.0
|
||||
RPC_BIND_PORT=8082
|
||||
P2P_BIND_HOST=0.0.0.0
|
||||
P2P_BIND_PORT=7070
|
||||
PROPOSER_KEY=proposer_key_$(date +%s)
|
||||
MINT_PER_UNIT=1000
|
||||
COORDINATOR_RATIO=0.05
|
||||
GOSSIP_BACKEND=memory
|
||||
EOL
|
||||
|
||||
# Create data directory
|
||||
mkdir -p data/devnet
|
||||
|
||||
# Setup Python environment
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install -e .
|
||||
|
||||
# Generate genesis
|
||||
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
|
||||
python scripts/make_genesis.py --output data/devnet/genesis.json --force
|
||||
EOF
|
||||
|
||||
# Create systemd service for blockchain node
|
||||
print_status "Creating systemd service for blockchain node..."
|
||||
ssh ns3-root << 'EOF'
|
||||
cat > /etc/systemd/system/blockchain-node.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain Node
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-node
|
||||
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
|
||||
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
cat > /etc/systemd/system/blockchain-rpc.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain RPC API
|
||||
After=blockchain-node.service
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-node
|
||||
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
|
||||
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable blockchain-node blockchain-rpc
|
||||
EOF
|
||||
|
||||
# Start blockchain node
|
||||
print_status "Starting blockchain node..."
|
||||
ssh ns3-root "systemctl start blockchain-node blockchain-rpc"
|
||||
|
||||
# Wait for node to start
|
||||
print_status "Waiting for blockchain node to start..."
|
||||
sleep 5
|
||||
|
||||
# Check status
|
||||
print_status "Checking blockchain node status..."
|
||||
ssh ns3-root "systemctl status blockchain-node blockchain-rpc --no-pager | grep -E 'Active:|Main PID:'"
|
||||
|
||||
# Copy explorer to container
|
||||
print_status "Copying blockchain explorer to container..."
|
||||
ssh ns3-root "rm -rf /opt/blockchain-explorer 2>/dev/null || true"
|
||||
scp -r apps/blockchain-explorer ns3-root:/opt/
|
||||
|
||||
# Setup explorer in container
|
||||
print_status "Setting up blockchain explorer..."
|
||||
ssh ns3-root << 'EOF'
|
||||
cd /opt/blockchain-explorer
|
||||
|
||||
# Create Python environment
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
EOF
|
||||
|
||||
# Create systemd service for explorer
|
||||
print_status "Creating systemd service for blockchain explorer..."
|
||||
ssh ns3-root << 'EOF'
|
||||
cat > /etc/systemd/system/blockchain-explorer.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain Explorer
|
||||
After=blockchain-rpc.service
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-explorer
|
||||
Environment=PATH=/opt/blockchain-explorer/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
ExecStart=/opt/blockchain-explorer/.venv/bin/python3 main.py
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable blockchain-explorer
|
||||
EOF
|
||||
|
||||
# Start explorer
|
||||
print_status "Starting blockchain explorer..."
|
||||
ssh ns3-root "systemctl start blockchain-explorer"
|
||||
|
||||
# Wait for explorer to start
|
||||
print_status "Waiting for explorer to start..."
|
||||
sleep 3
|
||||
|
||||
# Setup port forwarding
|
||||
print_status "Setting up port forwarding..."
|
||||
ssh ns3-root << 'EOF'
|
||||
# Clear existing NAT rules
|
||||
iptables -t nat -F PREROUTING 2>/dev/null || true
|
||||
iptables -t nat -F POSTROUTING 2>/dev/null || true
|
||||
|
||||
# Add port forwarding for blockchain RPC
|
||||
iptables -t nat -A PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082
|
||||
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE
|
||||
|
||||
# Add port forwarding for explorer
|
||||
iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000
|
||||
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE
|
||||
|
||||
# Save rules
|
||||
mkdir -p /etc/iptables
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
|
||||
# Install iptables-persistent for persistence
|
||||
apt-get update
|
||||
apt-get install -y iptables-persistent
|
||||
EOF
|
||||
|
||||
# Check all services
|
||||
print_status "Checking all services..."
|
||||
ssh ns3-root "systemctl status blockchain-node blockchain-rpc blockchain-explorer --no-pager | grep -E 'Active:|Main PID:'"
|
||||
|
||||
print_success "✅ Deployment complete!"
|
||||
echo ""
|
||||
echo "Services deployed:"
|
||||
echo " - Blockchain Node RPC: http://192.168.100.10:8082"
|
||||
echo " - Blockchain Explorer: http://192.168.100.10:3000"
|
||||
echo ""
|
||||
echo "External access:"
|
||||
echo " - Blockchain Node RPC: http://aitbc.keisanki.net:8082"
|
||||
echo " - Blockchain Explorer: http://aitbc.keisanki.net:3000"
|
||||
echo ""
|
||||
echo "The explorer is connected to the local blockchain node and will display"
|
||||
echo "real-time blockchain data including blocks and transactions."
|
||||
94
scripts/deploy/deploy-blockchain-explorer.sh
Executable file
94
scripts/deploy/deploy-blockchain-explorer.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy blockchain explorer to incus container
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔍 Deploying Blockchain Explorer"
|
||||
echo "================================="
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Copy explorer to container
|
||||
print_status "Copying blockchain explorer to container..."
|
||||
ssh ns3-root "rm -rf /opt/blockchain-explorer 2>/dev/null || true"
|
||||
scp -r apps/blockchain-explorer ns3-root:/opt/
|
||||
|
||||
# Setup explorer in container
|
||||
print_status "Setting up blockchain explorer..."
|
||||
ssh ns3-root << 'EOF'
|
||||
cd /opt/blockchain-explorer
|
||||
|
||||
# Create Python environment
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
EOF
|
||||
|
||||
# Create systemd service for explorer
|
||||
print_status "Creating systemd service for blockchain explorer..."
|
||||
ssh ns3-root << 'EOF'
|
||||
cat > /etc/systemd/system/blockchain-explorer.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain Explorer
|
||||
After=blockchain-rpc.service
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-explorer
|
||||
Environment=PATH=/opt/blockchain-explorer/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
ExecStart=/opt/blockchain-explorer/.venv/bin/python3 main.py
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable blockchain-explorer
|
||||
EOF
|
||||
|
||||
# Start explorer
|
||||
print_status "Starting blockchain explorer..."
|
||||
ssh ns3-root "systemctl start blockchain-explorer"
|
||||
|
||||
# Wait for explorer to start
|
||||
print_status "Waiting for explorer to start..."
|
||||
sleep 3
|
||||
|
||||
# Setup port forwarding for explorer
|
||||
print_status "Setting up port forwarding for explorer..."
|
||||
ssh ns3-root << 'EOF'
|
||||
# Add port forwarding for explorer
|
||||
iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000
|
||||
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE
|
||||
|
||||
# Save rules
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
EOF
|
||||
|
||||
# Check status
|
||||
print_status "Checking blockchain explorer status..."
|
||||
ssh ns3-root "systemctl status blockchain-explorer --no-pager | grep -E 'Active:|Main PID:'"
|
||||
|
||||
print_success "✅ Blockchain explorer deployed!"
|
||||
echo ""
|
||||
echo "Explorer URL: http://192.168.100.10:3000"
|
||||
echo "External URL: http://aitbc.keisanki.net:3000"
|
||||
echo ""
|
||||
echo "The explorer will automatically connect to the local blockchain node."
|
||||
echo "You can view blocks, transactions, and chain statistics."
|
||||
157
scripts/deploy/deploy-blockchain-remote.sh
Normal file
157
scripts/deploy/deploy-blockchain-remote.sh
Normal file
@@ -0,0 +1,157 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy blockchain node directly on ns3 server (build in place)
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Deploying Blockchain Node on ns3 (Build in Place)"
|
||||
echo "====================================================="
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if we're on the right server
|
||||
print_status "Checking server..."
|
||||
if [ "$(hostname)" != "ns3" ] && [ "$(hostname)" != "aitbc" ]; then
|
||||
print_warning "This script should be run on ns3 server"
|
||||
echo "Please run: ssh ns3-root"
|
||||
echo "Then: cd /opt && ./deploy-blockchain-remote.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install dependencies if needed
|
||||
print_status "Installing dependencies..."
|
||||
apt-get update
|
||||
apt-get install -y python3 python3-venv python3-pip git curl
|
||||
|
||||
# Create directory
|
||||
print_status "Creating blockchain node directory..."
|
||||
mkdir -p /opt/blockchain-node
|
||||
cd /opt/blockchain-node
|
||||
|
||||
# Check if source code exists
|
||||
if [ ! -d "src" ]; then
|
||||
print_status "Source code not found in /opt/blockchain-node, copying from /opt/blockchain-node-src..."
|
||||
if [ -d "/opt/blockchain-node-src" ]; then
|
||||
cp -r /opt/blockchain-node-src/* .
|
||||
else
|
||||
print_warning "Source code not found. Please ensure it was copied properly."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Setup Python environment
|
||||
print_status "Setting up Python environment..."
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install -e .
|
||||
|
||||
# Create configuration with auto-sync
|
||||
print_status "Creating configuration..."
|
||||
cat > .env << EOL
|
||||
CHAIN_ID=ait-devnet
|
||||
DB_PATH=./data/chain.db
|
||||
RPC_BIND_HOST=0.0.0.0
|
||||
RPC_BIND_PORT=8082
|
||||
P2P_BIND_HOST=0.0.0.0
|
||||
P2P_BIND_PORT=7070
|
||||
PROPOSER_KEY=proposer_key_$(date +%s)
|
||||
MINT_PER_UNIT=1000
|
||||
COORDINATOR_RATIO=0.05
|
||||
GOSSIP_BACKEND=memory
|
||||
EOL
|
||||
|
||||
# Create fresh data directory
|
||||
print_status "Creating fresh data directory..."
|
||||
rm -rf data
|
||||
mkdir -p data/devnet
|
||||
|
||||
# Generate fresh genesis
|
||||
print_status "Generating fresh genesis block..."
|
||||
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
|
||||
python scripts/make_genesis.py --output data/devnet/genesis.json --force
|
||||
|
||||
# Create systemd service for blockchain node
|
||||
print_status "Creating systemd services..."
|
||||
cat > /etc/systemd/system/blockchain-node.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain Node
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-node
|
||||
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
|
||||
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
cat > /etc/systemd/system/blockchain-rpc.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain RPC API
|
||||
After=blockchain-node.service
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-node
|
||||
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
|
||||
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
# Enable and start services
|
||||
print_status "Starting blockchain node..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable blockchain-node blockchain-rpc
|
||||
systemctl start blockchain-node blockchain-rpc
|
||||
|
||||
# Wait for services to start
|
||||
print_status "Waiting for services to start..."
|
||||
sleep 5
|
||||
|
||||
# Check status
|
||||
print_status "Checking service status..."
|
||||
systemctl status blockchain-node blockchain-rpc --no-pager | head -15
|
||||
|
||||
# Setup port forwarding if in container
|
||||
if [ "$(hostname)" = "aitbc" ]; then
|
||||
print_status "Setting up port forwarding..."
|
||||
iptables -t nat -A PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082
|
||||
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
fi
|
||||
|
||||
print_success "✅ Blockchain node deployed!"
|
||||
echo ""
|
||||
if [ "$(hostname)" = "aitbc" ]; then
|
||||
echo "Node RPC: http://192.168.100.10:8082"
|
||||
echo "External RPC: http://aitbc.keisanki.net:8082"
|
||||
else
|
||||
echo "Node RPC: http://95.216.198.140:8082"
|
||||
echo "External RPC: http://aitbc.keisanki.net:8082"
|
||||
fi
|
||||
echo ""
|
||||
echo "The node will automatically sync on startup."
|
||||
139
scripts/deploy/deploy-blockchain.sh
Executable file
139
scripts/deploy/deploy-blockchain.sh
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy blockchain node and explorer to incus container
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Deploying Blockchain Node and Explorer"
|
||||
echo "========================================"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Copy blockchain node to container
|
||||
print_status "Copying blockchain node to container..."
|
||||
ssh ns3-root "rm -rf /opt/blockchain-node 2>/dev/null || true"
|
||||
scp -r apps/blockchain-node ns3-root:/opt/
|
||||
|
||||
# Setup blockchain node in container
|
||||
print_status "Setting up blockchain node..."
|
||||
ssh ns3-root << 'EOF'
|
||||
cd /opt/blockchain-node
|
||||
|
||||
# Create configuration
|
||||
cat > .env << EOL
|
||||
CHAIN_ID=ait-devnet
|
||||
DB_PATH=./data/chain.db
|
||||
RPC_BIND_HOST=0.0.0.0
|
||||
RPC_BIND_PORT=8082
|
||||
P2P_BIND_HOST=0.0.0.0
|
||||
P2P_BIND_PORT=7070
|
||||
PROPOSER_KEY=proposer_key_$(date +%s)
|
||||
MINT_PER_UNIT=1000
|
||||
COORDINATOR_RATIO=0.05
|
||||
GOSSIP_BACKEND=memory
|
||||
EOL
|
||||
|
||||
# Create data directory
|
||||
mkdir -p data/devnet
|
||||
|
||||
# Setup Python environment
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install -e .
|
||||
|
||||
# Generate genesis
|
||||
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
|
||||
python scripts/make_genesis.py --output data/devnet/genesis.json --force
|
||||
EOF
|
||||
|
||||
# Create systemd service for blockchain node
|
||||
print_status "Creating systemd service for blockchain node..."
|
||||
ssh ns3-root << 'EOF'
|
||||
cat > /etc/systemd/system/blockchain-node.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain Node
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-node
|
||||
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
|
||||
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
cat > /etc/systemd/system/blockchain-rpc.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain RPC API
|
||||
After=blockchain-node.service
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-node
|
||||
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
|
||||
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable blockchain-node blockchain-rpc
|
||||
EOF
|
||||
|
||||
# Start blockchain node
|
||||
print_status "Starting blockchain node..."
|
||||
ssh ns3-root "systemctl start blockchain-node blockchain-rpc"
|
||||
|
||||
# Wait for node to start
|
||||
print_status "Waiting for blockchain node to start..."
|
||||
sleep 5
|
||||
|
||||
# Check status
|
||||
print_status "Checking blockchain node status..."
|
||||
ssh ns3-root "systemctl status blockchain-node blockchain-rpc --no-pager | grep -E 'Active:|Main PID:'"
|
||||
|
||||
# Setup port forwarding
|
||||
print_status "Setting up port forwarding..."
|
||||
ssh ns3-root << 'EOF'
|
||||
# Clear existing rules
|
||||
iptables -t nat -F PREROUTING 2>/dev/null || true
|
||||
iptables -t nat -F POSTROUTING 2>/dev/null || true
|
||||
|
||||
# Add port forwarding for blockchain RPC
|
||||
iptables -t nat -A PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082
|
||||
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE
|
||||
|
||||
# Save rules
|
||||
mkdir -p /etc/iptables
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
EOF
|
||||
|
||||
print_success "✅ Blockchain node deployed!"
|
||||
echo ""
|
||||
echo "Node RPC: http://192.168.100.10:8082"
|
||||
echo "External RPC: http://aitbc.keisanki.net:8082"
|
||||
echo ""
|
||||
echo "Next: Deploying blockchain explorer..."
|
||||
316
scripts/deploy/deploy-direct.sh
Executable file
316
scripts/deploy/deploy-direct.sh
Executable file
@@ -0,0 +1,316 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy blockchain node and explorer directly on ns3
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 AITBC Direct Deployment on ns3"
|
||||
echo "================================="
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if we're on ns3
|
||||
if [ "$(hostname)" != "ns3" ] && [ "$(hostname)" != "aitbc" ]; then
|
||||
print_warning "This script must be run on ns3 server"
|
||||
echo "Run: ssh ns3-root"
|
||||
echo "Then: cd /opt && ./deploy-direct.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Stop existing services
|
||||
print_status "Stopping existing services..."
|
||||
systemctl stop blockchain-node blockchain-rpc blockchain-explorer nginx 2>/dev/null || true
|
||||
|
||||
# Install dependencies
|
||||
print_status "Installing dependencies..."
|
||||
apt-get update
|
||||
apt-get install -y python3 python3-venv python3-pip git curl nginx
|
||||
|
||||
# Deploy blockchain node
|
||||
print_status "Deploying blockchain node..."
|
||||
cd /opt
|
||||
rm -rf blockchain-node
|
||||
cp -r blockchain-node-src blockchain-node
|
||||
cd blockchain-node
|
||||
|
||||
# Create configuration
|
||||
print_status "Creating configuration..."
|
||||
cat > .env << EOL
|
||||
CHAIN_ID=ait-devnet
|
||||
DB_PATH=./data/chain.db
|
||||
RPC_BIND_HOST=0.0.0.0
|
||||
RPC_BIND_PORT=8082
|
||||
P2P_BIND_HOST=0.0.0.0
|
||||
P2P_BIND_PORT=7070
|
||||
PROPOSER_KEY=proposer_key_$(date +%s)
|
||||
MINT_PER_UNIT=1000
|
||||
COORDINATOR_RATIO=0.05
|
||||
GOSSIP_BACKEND=memory
|
||||
EOL
|
||||
|
||||
# Create fresh data directory
|
||||
rm -rf data
|
||||
mkdir -p data/devnet
|
||||
|
||||
# Setup Python environment
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install -e .
|
||||
|
||||
# Generate genesis
|
||||
export PYTHONPATH="${PWD}/src:${PWD}/scripts:${PYTHONPATH:-}"
|
||||
python scripts/make_genesis.py --output data/devnet/genesis.json --force
|
||||
|
||||
# Create systemd services
|
||||
print_status "Creating systemd services..."
|
||||
cat > /etc/systemd/system/blockchain-node.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain Node
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-node
|
||||
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
|
||||
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m aitbc_chain.main
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
cat > /etc/systemd/system/blockchain-rpc.service << EOL
|
||||
[Unit]
|
||||
Description=AITBC Blockchain RPC API
|
||||
After=blockchain-node.service
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=root
|
||||
WorkingDirectory=/opt/blockchain-node
|
||||
Environment=PATH=/opt/blockchain-node/.venv/bin:/usr/local/bin:/usr/bin:/bin
|
||||
Environment=PYTHONPATH=/opt/blockchain-node/src:/opt/blockchain-node/scripts
|
||||
ExecStart=/opt/blockchain-node/.venv/bin/python3 -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 8082
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
# Start blockchain services
|
||||
print_status "Starting blockchain services..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable blockchain-node blockchain-rpc
|
||||
systemctl start blockchain-node blockchain-rpc
|
||||
|
||||
# Deploy explorer
|
||||
print_status "Deploying blockchain explorer..."
|
||||
cd /opt
|
||||
rm -rf blockchain-explorer
|
||||
mkdir -p blockchain-explorer
|
||||
cd blockchain-explorer
|
||||
|
||||
# Create HTML explorer
|
||||
cat > index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AITBC Blockchain Explorer</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/lucide@latest"></script>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-blue-600 text-white shadow-lg">
|
||||
<div class="container mx-auto px-4 py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center space-x-3">
|
||||
<i data-lucide="cube" class="w-8 h-8"></i>
|
||||
<h1 class="text-2xl font-bold">AITBC Blockchain Explorer</h1>
|
||||
</div>
|
||||
<button onclick="refreshData()" class="bg-blue-500 hover:bg-blue-400 px-3 py-1 rounded flex items-center space-x-1">
|
||||
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
|
||||
<span>Refresh</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container mx-auto px-4 py-8">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-gray-500 text-sm">Current Height</p>
|
||||
<p class="text-2xl font-bold" id="chain-height">-</p>
|
||||
</div>
|
||||
<i data-lucide="trending-up" class="w-10 h-10 text-green-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-gray-500 text-sm">Latest Block</p>
|
||||
<p class="text-lg font-mono" id="latest-hash">-</p>
|
||||
</div>
|
||||
<i data-lucide="hash" class="w-10 h-10 text-blue-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-gray-500 text-sm">Node Status</p>
|
||||
<p class="text-lg font-semibold" id="node-status">-</p>
|
||||
</div>
|
||||
<i data-lucide="activity" class="w-10 h-10 text-purple-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow">
|
||||
<div class="px-6 py-4 border-b">
|
||||
<h2 class="text-xl font-semibold flex items-center">
|
||||
<i data-lucide="blocks" class="w-5 h-5 mr-2"></i>
|
||||
Latest Blocks
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="text-left text-gray-500 text-sm">
|
||||
<th class="pb-3">Height</th>
|
||||
<th class="pb-3">Hash</th>
|
||||
<th class="pb-3">Timestamp</th>
|
||||
<th class="pb-3">Transactions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="blocks-table">
|
||||
<tr>
|
||||
<td colspan="4" class="text-center py-8 text-gray-500">
|
||||
Loading blocks...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
lucide.createIcons();
|
||||
|
||||
const RPC_URL = 'http://localhost:8082';
|
||||
|
||||
async function refreshData() {
|
||||
try {
|
||||
const response = await fetch(`${RPC_URL}/rpc/head`);
|
||||
const head = await response.json();
|
||||
|
||||
document.getElementById('chain-height').textContent = head.height || '-';
|
||||
document.getElementById('latest-hash').textContent = head.hash ? head.hash.substring(0, 16) + '...' : '-';
|
||||
document.getElementById('node-status').innerHTML = '<span class="text-green-500">Online</span>';
|
||||
|
||||
// Load last 10 blocks
|
||||
const tbody = document.getElementById('blocks-table');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
for (let i = 0; i < 10 && head.height - i >= 0; i++) {
|
||||
const blockResponse = await fetch(`${RPC_URL}/rpc/blocks/${head.height - i}`);
|
||||
const block = await blockResponse.json();
|
||||
|
||||
const row = tbody.insertRow();
|
||||
row.innerHTML = `
|
||||
<td class="py-3 font-mono">${block.height}</td>
|
||||
<td class="py-3 font-mono text-sm">${block.hash ? block.hash.substring(0, 16) + '...' : '-'}</td>
|
||||
<td class="py-3 text-sm">${new Date(block.timestamp * 1000).toLocaleString()}</td>
|
||||
<td class="py-3">${block.transactions ? block.transactions.length : 0}</td>
|
||||
`;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
document.getElementById('node-status').innerHTML = '<span class="text-red-500">Error</span>';
|
||||
}
|
||||
}
|
||||
|
||||
refreshData();
|
||||
setInterval(refreshData, 30000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
# Configure nginx
|
||||
print_status "Configuring nginx..."
|
||||
cat > /etc/nginx/sites-available/blockchain-explorer << EOL
|
||||
server {
|
||||
listen 3000;
|
||||
server_name _;
|
||||
root /opt/blockchain-explorer;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ =404;
|
||||
}
|
||||
}
|
||||
EOL
|
||||
|
||||
ln -sf /etc/nginx/sites-available/blockchain-explorer /etc/nginx/sites-enabled/
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
nginx -t
|
||||
systemctl reload nginx
|
||||
|
||||
# Setup port forwarding if in container
|
||||
if [ "$(hostname)" = "aitbc" ]; then
|
||||
print_status "Setting up port forwarding..."
|
||||
iptables -t nat -F PREROUTING 2>/dev/null || true
|
||||
iptables -t nat -F POSTROUTING 2>/dev/null || true
|
||||
iptables -t nat -A PREROUTING -p tcp --dport 8082 -j DNAT --to-destination 192.168.100.10:8082
|
||||
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 8082 -j MASQUERADE
|
||||
iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000
|
||||
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
fi
|
||||
|
||||
# Wait for services to start
|
||||
print_status "Waiting for services to start..."
|
||||
sleep 5
|
||||
|
||||
# Check services
|
||||
print_status "Checking service status..."
|
||||
systemctl status blockchain-node blockchain-rpc nginx --no-pager | grep -E 'Active:|Main PID:'
|
||||
|
||||
print_success "✅ Deployment complete!"
|
||||
echo ""
|
||||
echo "Services:"
|
||||
if [ "$(hostname)" = "aitbc" ]; then
|
||||
echo " - Blockchain Node RPC: http://192.168.100.10:8082"
|
||||
echo " - Blockchain Explorer: http://192.168.100.10:3000"
|
||||
echo ""
|
||||
echo "External access:"
|
||||
echo " - Blockchain Node RPC: http://aitbc.keisanki.net:8082"
|
||||
echo " - Blockchain Explorer: http://aitbc.keisanki.net:3000"
|
||||
else
|
||||
echo " - Blockchain Node RPC: http://localhost:8082"
|
||||
echo " - Blockchain Explorer: http://localhost:3000"
|
||||
echo ""
|
||||
echo "External access:"
|
||||
echo " - Blockchain Node RPC: http://aitbc.keisanki.net:8082"
|
||||
echo " - Blockchain Explorer: http://aitbc.keisanki.net:3000"
|
||||
fi
|
||||
88
scripts/deploy/deploy-domain.sh
Executable file
88
scripts/deploy/deploy-domain.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy AITBC services to domain https://aitbc.bubuit.net
|
||||
|
||||
set -e
|
||||
|
||||
DOMAIN="aitbc.bubuit.net"
|
||||
CONTAINER="aitbc"
|
||||
|
||||
echo "🚀 Deploying AITBC services to https://$DOMAIN"
|
||||
echo ""
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Stop local services
|
||||
print_status "Stopping local services..."
|
||||
sudo fuser -k 8000/tcp 2>/dev/null || true
|
||||
sudo fuser -k 9080/tcp 2>/dev/null || true
|
||||
sudo fuser -k 3001/tcp 2>/dev/null || true
|
||||
sudo fuser -k 3002/tcp 2>/dev/null || true
|
||||
|
||||
# Deploy to container
|
||||
print_status "Deploying to container..."
|
||||
python /home/oib/windsurf/aitbc/container-deploy.py
|
||||
|
||||
# Copy nginx config to container
|
||||
print_status "Configuring nginx for domain..."
|
||||
incus file push /home/oib/windsurf/aitbc/nginx-aitbc.conf $CONTAINER/etc/nginx/sites-available/aitbc
|
||||
|
||||
# Enable site
|
||||
incus exec $CONTAINER -- ln -sf /etc/nginx/sites-available/aitbc /etc/nginx/sites-enabled/
|
||||
incus exec $CONTAINER -- rm -f /etc/nginx/sites-enabled/default
|
||||
|
||||
# Test nginx config
|
||||
incus exec $CONTAINER -- nginx -t
|
||||
|
||||
# Reload nginx
|
||||
incus exec $CONTAINER -- systemctl reload nginx
|
||||
|
||||
# Install SSL certificate (Let's Encrypt)
|
||||
print_warning "SSL Certificate Setup:"
|
||||
echo "1. Ensure port 80/443 are forwarded to container IP (10.1.223.93)"
|
||||
echo "2. Run certbot in container:"
|
||||
echo " incus exec $CONTAINER -- certbot --nginx -d $DOMAIN"
|
||||
echo ""
|
||||
|
||||
# Update UIs to use correct API endpoints
|
||||
print_status "Updating API endpoints..."
|
||||
|
||||
# Update marketplace API base URL
|
||||
incus exec $CONTAINER -- sed -i "s|http://127.0.0.1:8000|https://$DOMAIN/api|g" /home/oib/aitbc/apps/marketplace-ui/index.html
|
||||
|
||||
# Update exchange API endpoints
|
||||
incus exec $CONTAINER -- sed -i "s|http://127.0.0.1:8000|https://$DOMAIN/api|g" /home/oib/aitbc/apps/trade-exchange/index.html
|
||||
incus exec $CONTAINER -- sed -i "s|http://127.0.0.1:9080|https://$DOMAIN/rpc|g" /home/oib/aitbc/apps/trade-exchange/index.html
|
||||
|
||||
# Restart services to apply changes
|
||||
print_status "Restarting services..."
|
||||
incus exec $CONTAINER -- pkill -f "server.py"
|
||||
sleep 2
|
||||
incus exec $CONTAINER -- /home/oib/start_aitbc.sh
|
||||
|
||||
echo ""
|
||||
print_status "✅ Deployment complete!"
|
||||
echo ""
|
||||
echo "📋 Service URLs:"
|
||||
echo " 🌐 Domain: https://$DOMAIN"
|
||||
echo " 📊 Marketplace: https://$DOMAIN/Marketplace"
|
||||
echo " 💱 Trade Exchange: https://$DOMAIN/Exchange"
|
||||
echo " 🔗 API: https://$DOMAIN/api"
|
||||
echo " ⛓️ Blockchain RPC: https://$DOMAIN/rpc"
|
||||
echo ""
|
||||
echo "📝 Next Steps:"
|
||||
echo "1. Forward ports 80/443 to container IP (10.1.223.93)"
|
||||
echo "2. Install SSL certificate:"
|
||||
echo " incus exec $CONTAINER -- certbot --nginx -d $DOMAIN"
|
||||
echo "3. Test services at the URLs above"
|
||||
74
scripts/deploy/deploy-exchange.sh
Executable file
74
scripts/deploy/deploy-exchange.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy AITBC Trade Exchange to the server
|
||||
|
||||
set -e
|
||||
|
||||
SERVER="root@10.1.223.93"
|
||||
EXCHANGE_DIR="/root/aitbc/apps/trade-exchange"
|
||||
|
||||
echo "🚀 Deploying AITBC Trade Exchange"
|
||||
echo "=================================="
|
||||
echo "Server: $SERVER"
|
||||
echo ""
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Test SSH connection
|
||||
print_status "Testing SSH connection..."
|
||||
ssh $SERVER "hostname && ip a show eth0 | grep inet"
|
||||
|
||||
# Copy updated files
|
||||
print_status "Copying updated Exchange files..."
|
||||
scp /home/oib/windsurf/aitbc/apps/trade-exchange/index.html $SERVER:$EXCHANGE_DIR/
|
||||
scp /home/oib/windsurf/aitbc/apps/trade-exchange/server.py $SERVER:$EXCHANGE_DIR/
|
||||
|
||||
# Ensure assets are available
|
||||
print_status "Ensuring assets directory exists..."
|
||||
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets"
|
||||
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets/css"
|
||||
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets/js"
|
||||
|
||||
# Copy assets if they don't exist
|
||||
print_status "Copying assets if needed..."
|
||||
if ! ssh $SERVER "test -f /var/www/aitbc.bubuit.net/assets/css/aitbc.css"; then
|
||||
scp -r /home/oib/windsurf/aitbc/assets/* $SERVER:/var/www/aitbc.bubuit.net/assets/
|
||||
fi
|
||||
|
||||
# Restart the exchange service
|
||||
print_status "Restarting Trade Exchange service..."
|
||||
ssh $SERVER "systemctl restart aitbc-exchange"
|
||||
|
||||
# Wait for service to start
|
||||
print_status "Waiting for service to start..."
|
||||
sleep 5
|
||||
|
||||
# Check service status
|
||||
print_status "Checking service status..."
|
||||
ssh $SERVER "systemctl status aitbc-exchange --no-pager -l | head -10"
|
||||
|
||||
# Test the endpoint
|
||||
print_status "Testing Exchange endpoint..."
|
||||
ssh $SERVER "curl -s http://127.0.0.1:3002/ | head -c 100"
|
||||
echo ""
|
||||
|
||||
echo ""
|
||||
print_status "✅ Exchange deployment complete!"
|
||||
echo ""
|
||||
echo "📋 URLs:"
|
||||
echo " 🌐 IP: http://10.1.223.93/Exchange"
|
||||
echo " 🔒 Domain: https://aitbc.bubuit.net/Exchange"
|
||||
echo ""
|
||||
echo "🔍 To check logs:"
|
||||
echo " ssh $SERVER 'journalctl -u aitbc-exchange -f'"
|
||||
396
scripts/deploy/deploy-explorer-remote.sh
Normal file
396
scripts/deploy/deploy-explorer-remote.sh
Normal file
@@ -0,0 +1,396 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy blockchain explorer directly on ns3 server
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔍 Deploying Blockchain Explorer on ns3"
|
||||
echo "======================================"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if we're on the right server
|
||||
if [ "$(hostname)" != "ns3" ] && [ "$(hostname)" != "aitbc" ]; then
|
||||
print_warning "This script should be run on ns3 server"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create directory
|
||||
print_status "Creating blockchain explorer directory..."
|
||||
mkdir -p /opt/blockchain-explorer
|
||||
cd /opt/blockchain-explorer
|
||||
|
||||
# Create a simple HTML-based explorer (no build needed)
|
||||
print_status "Creating web-based explorer..."
|
||||
cat > index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AITBC Blockchain Explorer</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/lucide@latest"></script>
|
||||
<style>
|
||||
.fade-in { animation: fadeIn 0.3s ease-in; }
|
||||
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-blue-600 text-white shadow-lg">
|
||||
<div class="container mx-auto px-4 py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center space-x-3">
|
||||
<i data-lucide="cube" class="w-8 h-8"></i>
|
||||
<h1 class="text-2xl font-bold">AITBC Blockchain Explorer</h1>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<span class="text-sm">Network: <span class="font-mono bg-blue-700 px-2 py-1 rounded">ait-devnet</span></span>
|
||||
<button onclick="refreshData()" class="bg-blue-500 hover:bg-blue-400 px-3 py-1 rounded flex items-center space-x-1">
|
||||
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
|
||||
<span>Refresh</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container mx-auto px-4 py-8">
|
||||
<!-- Chain Stats -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-gray-500 text-sm">Current Height</p>
|
||||
<p class="text-2xl font-bold" id="chain-height">-</p>
|
||||
</div>
|
||||
<i data-lucide="trending-up" class="w-10 h-10 text-green-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-gray-500 text-sm">Latest Block</p>
|
||||
<p class="text-lg font-mono" id="latest-hash">-</p>
|
||||
</div>
|
||||
<i data-lucide="hash" class="w-10 h-10 text-blue-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-gray-500 text-sm">Node Status</p>
|
||||
<p class="text-lg font-semibold" id="node-status">-</p>
|
||||
</div>
|
||||
<i data-lucide="activity" class="w-10 h-10 text-purple-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search -->
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-8">
|
||||
<div class="flex space-x-4">
|
||||
<input type="text" id="search-input" placeholder="Search by block height, hash, or transaction hash"
|
||||
class="flex-1 px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<button onclick="search()" class="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Latest Blocks -->
|
||||
<div class="bg-white rounded-lg shadow">
|
||||
<div class="px-6 py-4 border-b">
|
||||
<h2 class="text-xl font-semibold flex items-center">
|
||||
<i data-lucide="blocks" class="w-5 h-5 mr-2"></i>
|
||||
Latest Blocks
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="text-left text-gray-500 text-sm">
|
||||
<th class="pb-3">Height</th>
|
||||
<th class="pb-3">Hash</th>
|
||||
<th class="pb-3">Timestamp</th>
|
||||
<th class="pb-3">Transactions</th>
|
||||
<th class="pb-3">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="blocks-table">
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-8 text-gray-500">
|
||||
Loading blocks...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Block Details Modal -->
|
||||
<div id="block-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50">
|
||||
<div class="flex items-center justify-center min-h-screen p-4">
|
||||
<div class="bg-white rounded-lg max-w-4xl w-full max-h-[90vh] overflow-y-auto">
|
||||
<div class="p-6 border-b">
|
||||
<div class="flex justify-between items-center">
|
||||
<h2 class="text-2xl font-bold">Block Details</h2>
|
||||
<button onclick="closeModal()" class="text-gray-500 hover:text-gray-700">
|
||||
<i data-lucide="x" class="w-6 h-6"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6" id="block-details">
|
||||
<!-- Block details will be loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="bg-gray-800 text-white mt-12">
|
||||
<div class="container mx-auto px-4 py-6 text-center">
|
||||
<p class="text-sm">AITBC Blockchain Explorer - Connected to node at http://localhost:8082</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
// Initialize lucide icons
|
||||
lucide.createIcons();
|
||||
|
||||
// RPC URL - change based on environment
|
||||
const RPC_URL = window.location.hostname === 'localhost' ?
|
||||
'http://localhost:8082' :
|
||||
'http://95.216.198.140:8082';
|
||||
|
||||
// Global state
|
||||
let currentData = {};
|
||||
|
||||
// Load initial data
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
refreshData();
|
||||
});
|
||||
|
||||
// Refresh all data
|
||||
async function refreshData() {
|
||||
try {
|
||||
await Promise.all([
|
||||
loadChainStats(),
|
||||
loadLatestBlocks()
|
||||
]);
|
||||
} catch (error) {
|
||||
console.error('Error refreshing data:', error);
|
||||
document.getElementById('node-status').innerHTML = '<span class="text-red-500">Error</span>';
|
||||
}
|
||||
}
|
||||
|
||||
// Load chain statistics
|
||||
async function loadChainStats() {
|
||||
const response = await fetch(`${RPC_URL}/rpc/head`);
|
||||
const data = await response.json();
|
||||
|
||||
document.getElementById('chain-height').textContent = data.height || '-';
|
||||
document.getElementById('latest-hash').textContent = data.hash ? data.hash.substring(0, 16) + '...' : '-';
|
||||
document.getElementById('node-status').innerHTML = '<span class="text-green-500">Online</span>';
|
||||
|
||||
currentData.head = data;
|
||||
}
|
||||
|
||||
// Load latest blocks
|
||||
async function loadLatestBlocks() {
|
||||
const tbody = document.getElementById('blocks-table');
|
||||
tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-gray-500">Loading blocks...</td></tr>';
|
||||
|
||||
const head = await fetch(`${RPC_URL}/rpc/head`).then(r => r.json());
|
||||
const blocks = [];
|
||||
|
||||
// Load last 10 blocks
|
||||
for (let i = 0; i < 10 && head.height - i >= 0; i++) {
|
||||
const block = await fetch(`${RPC_URL}/rpc/blocks/${head.height - i}`).then(r => r.json());
|
||||
blocks.push(block);
|
||||
}
|
||||
|
||||
tbody.innerHTML = blocks.map(block => `
|
||||
<tr class="border-t hover:bg-gray-50">
|
||||
<td class="py-3 font-mono">${block.height}</td>
|
||||
<td class="py-3 font-mono text-sm">${block.hash ? block.hash.substring(0, 16) + '...' : '-'}</td>
|
||||
<td class="py-3 text-sm">${formatTimestamp(block.timestamp)}</td>
|
||||
<td class="py-3">${block.transactions ? block.transactions.length : 0}</td>
|
||||
<td class="py-3">
|
||||
<button onclick="showBlockDetails(${block.height})" class="text-blue-600 hover:text-blue-800">
|
||||
View Details
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// Show block details
|
||||
async function showBlockDetails(height) {
|
||||
const block = await fetch(`${RPC_URL}/rpc/blocks/${height}`).then(r => r.json());
|
||||
const modal = document.getElementById('block-modal');
|
||||
const details = document.getElementById('block-details');
|
||||
|
||||
details.innerHTML = `
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold mb-2">Block Header</h3>
|
||||
<div class="bg-gray-50 rounded p-4 space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Height:</span>
|
||||
<span class="font-mono">${block.height}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Hash:</span>
|
||||
<span class="font-mono text-sm">${block.hash || '-'}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Parent Hash:</span>
|
||||
<span class="font-mono text-sm">${block.parent_hash || '-'}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Timestamp:</span>
|
||||
<span>${formatTimestamp(block.timestamp)}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Proposer:</span>
|
||||
<span class="font-mono text-sm">${block.proposer || '-'}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${block.transactions && block.transactions.length > 0 ? `
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold mb-2">Transactions (${block.transactions.length})</h3>
|
||||
<div class="space-y-2">
|
||||
${block.transactions.map(tx => `
|
||||
<div class="bg-gray-50 rounded p-4">
|
||||
<div class="flex justify-between mb-2">
|
||||
<span class="text-gray-600">Hash:</span>
|
||||
<span class="font-mono text-sm">${tx.hash || '-'}</span>
|
||||
</div>
|
||||
<div class="flex justify-between mb-2">
|
||||
<span class="text-gray-600">Type:</span>
|
||||
<span>${tx.type || '-'}</span>
|
||||
</div>
|
||||
<div class="flex justify-between mb-2">
|
||||
<span class="text-gray-600">From:</span>
|
||||
<span class="font-mono text-sm">${tx.sender || '-'}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Fee:</span>
|
||||
<span>${tx.fee || '0'}</span>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
` : '<p class="text-gray-500">No transactions in this block</p>'}
|
||||
</div>
|
||||
`;
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
}
|
||||
|
||||
// Close modal
|
||||
function closeModal() {
|
||||
document.getElementById('block-modal').classList.add('hidden');
|
||||
}
|
||||
|
||||
// Search functionality
|
||||
async function search() {
|
||||
const query = document.getElementById('search-input').value.trim();
|
||||
if (!query) return;
|
||||
|
||||
// Try block height first
|
||||
if (/^\\d+$/.test(query)) {
|
||||
showBlockDetails(parseInt(query));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Add transaction hash search
|
||||
alert('Search by block height is currently supported');
|
||||
}
|
||||
|
||||
// Format timestamp
|
||||
function formatTimestamp(timestamp) {
|
||||
if (!timestamp) return '-';
|
||||
return new Date(timestamp * 1000).toLocaleString();
|
||||
}
|
||||
|
||||
// Auto-refresh every 30 seconds
|
||||
setInterval(refreshData, 30000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
# Install a simple web server
|
||||
print_status "Installing web server..."
|
||||
apt-get install -y nginx
|
||||
|
||||
# Configure nginx to serve the explorer
|
||||
print_status "Configuring nginx..."
|
||||
cat > /etc/nginx/sites-available/blockchain-explorer << EOL
|
||||
server {
|
||||
listen 3000;
|
||||
server_name _;
|
||||
root /opt/blockchain-explorer;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ =404;
|
||||
}
|
||||
|
||||
# CORS headers for API access
|
||||
location /rpc/ {
|
||||
proxy_pass http://localhost:8082;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
EOL
|
||||
|
||||
# Enable the site
|
||||
ln -sf /etc/nginx/sites-available/blockchain-explorer /etc/nginx/sites-enabled/
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
|
||||
# Test and reload nginx
|
||||
nginx -t
|
||||
systemctl reload nginx
|
||||
|
||||
# Setup port forwarding if in container
|
||||
if [ "$(hostname)" = "aitbc" ]; then
|
||||
print_status "Setting up port forwarding..."
|
||||
iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 192.168.100.10:3000
|
||||
iptables -t nat -A POSTROUTING -p tcp -d 192.168.100.10 --dport 3000 -j MASQUERADE
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
fi
|
||||
|
||||
print_status "Checking nginx status..."
|
||||
systemctl status nginx --no-pager | head -10
|
||||
|
||||
print_success "✅ Blockchain explorer deployed!"
|
||||
echo ""
|
||||
echo "Explorer URL: http://localhost:3000"
|
||||
if [ "$(hostname)" = "aitbc" ]; then
|
||||
echo "External URL: http://aitbc.keisanki.net:3000"
|
||||
else
|
||||
echo "External URL: http://aitbc.keisanki.net:3000"
|
||||
fi
|
||||
echo ""
|
||||
echo "The explorer is a static HTML site served by nginx."
|
||||
66
scripts/deploy/deploy-explorer.sh
Executable file
66
scripts/deploy/deploy-explorer.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy AITBC Explorer to the server
|
||||
|
||||
set -e
|
||||
|
||||
SERVER="root@10.1.223.93"
|
||||
EXPLORER_DIR="/root/aitbc/apps/explorer-web"
|
||||
NGINX_CONFIG="/etc/nginx/sites-available/aitbc"
|
||||
|
||||
echo "🚀 Deploying AITBC Explorer to Server"
|
||||
echo "====================================="
|
||||
echo "Server: $SERVER"
|
||||
echo ""
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
# Build the explorer locally first
|
||||
print_status "Building explorer locally..."
|
||||
cd /home/oib/windsurf/aitbc/apps/explorer-web
|
||||
npm run build
|
||||
|
||||
# Copy built files to server
|
||||
print_status "Copying explorer build to server..."
|
||||
scp -r dist $SERVER:$EXPLORER_DIR/
|
||||
|
||||
# Update nginx config to include explorer
|
||||
print_status "Updating nginx configuration..."
|
||||
|
||||
# Backup current config
|
||||
ssh $SERVER "cp $NGINX_CONFIG ${NGINX_CONFIG}.backup"
|
||||
|
||||
# Add explorer location to nginx config
|
||||
ssh $SERVER "sed -i '/# Health endpoint/i\\
|
||||
# Explorer\\
|
||||
location /explorer/ {\\
|
||||
alias /root/aitbc/apps/explorer-web/dist/;\\
|
||||
try_files \$uri \$uri/ /explorer/index.html;\\
|
||||
}\\
|
||||
\\
|
||||
# Explorer mock data\\
|
||||
location /explorer/mock/ {\\
|
||||
alias /root/aitbc/apps/explorer-web/public/mock/;\\
|
||||
}\\
|
||||
' $NGINX_CONFIG"
|
||||
|
||||
# Test and reload nginx
|
||||
print_status "Testing and reloading nginx..."
|
||||
ssh $SERVER "nginx -t && systemctl reload nginx"
|
||||
|
||||
print_status "✅ Explorer deployment complete!"
|
||||
echo ""
|
||||
echo "📋 Explorer URL:"
|
||||
echo " 🌐 Explorer: https://aitbc.bubuit.net/explorer/"
|
||||
echo ""
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user