Setup Oracle server
This commit is contained in:
parent
98eeb8b38b
commit
5710f1d83d
41
.env.example
41
.env.example
|
|
@ -1 +1,40 @@
|
|||
OPENAI_API_KEY=sk-proj...
|
||||
# Natural Language Agreement Oracle Configuration
|
||||
|
||||
# ================================
|
||||
# DEPLOYMENT CONFIGURATION
|
||||
# ================================
|
||||
|
||||
# Deployer's private key (used for contract deployment)
|
||||
# IMPORTANT: This should be a funded account with enough ETH for gas
|
||||
# NEVER commit your real private key!
|
||||
# The key below is from Anvil's default accounts - DO NOT USE IN PRODUCTION
|
||||
DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
|
||||
|
||||
# ================================
|
||||
# ORACLE CONFIGURATION
|
||||
# ================================
|
||||
|
||||
# Blockchain RPC URL (required for oracle)
|
||||
# Examples:
|
||||
# Local: http://localhost:8545
|
||||
# Sepolia: https://sepolia.infura.io/v3/YOUR-INFURA-KEY
|
||||
# Mainnet: https://mainnet.infura.io/v3/YOUR-INFURA-KEY
|
||||
RPC_URL=http://localhost:8545
|
||||
|
||||
# Oracle operator's private key (required for oracle)
|
||||
# This account submits arbitration decisions on-chain
|
||||
# IMPORTANT: Ensure this account has sufficient ETH for gas!
|
||||
# The key below is from Anvil's default accounts - DO NOT USE IN PRODUCTION
|
||||
ORACLE_PRIVATE_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
|
||||
|
||||
# EAS (Ethereum Attestation Service) Contract Address (optional)
|
||||
# If you used the deploy script, get this from deployments/<network>.json
|
||||
# EAS_CONTRACT_ADDRESS=0x...
|
||||
|
||||
# ================================
|
||||
# AI CONFIGURATION
|
||||
# ================================
|
||||
|
||||
# OpenAI API Key (required for oracle)
|
||||
# Get your API key from https://platform.openai.com/api-keys
|
||||
OPENAI_API_KEY=sk-proj...
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ coverage
|
|||
logs
|
||||
_.log
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
anvil.log
|
||||
|
||||
# process ids
|
||||
*.pid
|
||||
.anvil.pid
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
# Quick Start Guide
|
||||
|
||||
Get your Natural Language Agreement Oracle running in **under 2 minutes**!
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Bun](https://bun.sh) installed
|
||||
- [Foundry](https://book.getfoundry.sh/getting-started/installation) installed
|
||||
- Both `alkahest` and `natural-language-agreements` repos cloned in same parent directory
|
||||
- OpenAI API key
|
||||
|
||||
## One-Command Setup
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY=sk-your-key-here
|
||||
./scripts/dev.sh
|
||||
```
|
||||
|
||||
Done! The oracle is now running and listening for arbitration requests.
|
||||
|
||||
**To stop:**
|
||||
```bash
|
||||
./scripts/stop.sh
|
||||
```
|
||||
|
||||
## What Just Happened?
|
||||
|
||||
The script:
|
||||
1. ✅ Checked prerequisites
|
||||
2. ✅ Started Anvil (local blockchain)
|
||||
3. ✅ Deployed all contracts
|
||||
4. ✅ Started the oracle
|
||||
|
||||
## Test It
|
||||
|
||||
In another terminal:
|
||||
```bash
|
||||
bun test tests/nlaOracle.test.ts
|
||||
```
|
||||
|
||||
Watch the oracle terminal to see it process the arbitration!
|
||||
|
||||
## Manual Steps (Optional)
|
||||
|
||||
If you want more control:
|
||||
|
||||
```bash
|
||||
# Terminal 1: Blockchain
|
||||
anvil
|
||||
|
||||
# Terminal 2: Deploy and start oracle
|
||||
bun run deploy
|
||||
bun run oracle
|
||||
|
||||
# Terminal 3: Test
|
||||
bun test tests/nlaOracle.test.ts
|
||||
```
|
||||
|
||||
## Deploy to Testnet
|
||||
|
||||
```bash
|
||||
# Get Sepolia ETH from faucet first
|
||||
export DEPLOYER_PRIVATE_KEY=0x...
|
||||
bun run setups/deploy.ts --network sepolia --rpc-url https://sepolia.infura.io/v3/YOUR-KEY
|
||||
|
||||
# Start oracle
|
||||
export ORACLE_PRIVATE_KEY=0x...
|
||||
export OPENAI_API_KEY=sk-...
|
||||
bun run setups/oracle.ts sepolia
|
||||
```
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Full docs: [README.md](README.md)
|
||||
- Example test: `tests/nlaOracle.test.ts`
|
||||
232
README.md
232
README.md
|
|
@ -41,8 +41,188 @@ cd natural-language-agreements
|
|||
bun install
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Option 1: Automated Setup (Easiest - 1 command!)
|
||||
|
||||
Set your OpenAI API key and run everything:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY=sk-your-key-here
|
||||
./scripts/dev.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
- ✅ Check all prerequisites
|
||||
- ✅ Start Anvil (local blockchain)
|
||||
- ✅ Deploy all contracts
|
||||
- ✅ Start the oracle
|
||||
- ✅ Ready to test!
|
||||
|
||||
To stop everything:
|
||||
```bash
|
||||
./scripts/stop.sh
|
||||
```
|
||||
|
||||
### Option 2: Manual Setup (Step by Step)
|
||||
|
||||
#### 1. Start Local Blockchain
|
||||
|
||||
```bash
|
||||
# Terminal 1: Start Anvil
|
||||
anvil
|
||||
```
|
||||
|
||||
#### 2. Deploy Contracts
|
||||
|
||||
```bash
|
||||
# Terminal 2: Deploy to localhost
|
||||
export OPENAI_API_KEY=sk-your-key-here
|
||||
./scripts/deploy.sh localhost
|
||||
```
|
||||
|
||||
This creates `deployments/localhost.json` with all contract addresses.
|
||||
|
||||
#### 3. Start Oracle
|
||||
|
||||
```bash
|
||||
# Terminal 2 (or 3): Start oracle
|
||||
./scripts/start-oracle.sh localhost
|
||||
```
|
||||
|
||||
#### 4. Test It
|
||||
|
||||
```bash
|
||||
# Terminal 3 (or 4): Run tests
|
||||
bun test tests/nlaOracle.test.ts
|
||||
```
|
||||
|
||||
Watch the oracle terminal - you'll see it process arbitration requests in real-time!
|
||||
|
||||
## Deployment to Other Networks
|
||||
|
||||
### Sepolia Testnet
|
||||
|
||||
```bash
|
||||
# 1. Get Sepolia ETH from faucet
|
||||
# 2. Set your keys
|
||||
export DEPLOYER_PRIVATE_KEY=0x...
|
||||
export ORACLE_PRIVATE_KEY=0x...
|
||||
export OPENAI_API_KEY=sk-...
|
||||
|
||||
# 3. Deploy
|
||||
./scripts/deploy.sh sepolia https://sepolia.infura.io/v3/YOUR-KEY
|
||||
|
||||
# 4. Start oracle
|
||||
./scripts/start-oracle.sh sepolia
|
||||
```
|
||||
|
||||
### Mainnet
|
||||
|
||||
```bash
|
||||
# ⚠️ PRODUCTION - Be careful!
|
||||
export DEPLOYER_PRIVATE_KEY=0x...
|
||||
export ORACLE_PRIVATE_KEY=0x...
|
||||
export OPENAI_API_KEY=sk-...
|
||||
|
||||
# Deploy
|
||||
./scripts/deploy.sh mainnet https://mainnet.infura.io/v3/YOUR-KEY
|
||||
|
||||
# Start oracle (consider running as a service)
|
||||
./scripts/start-oracle.sh mainnet
|
||||
```
|
||||
|
||||
## Available Scripts
|
||||
|
||||
```bash
|
||||
./scripts/dev.sh # Complete local setup (all-in-one)
|
||||
./scripts/deploy.sh [network] # Deploy contracts to network
|
||||
./scripts/start-oracle.sh [network] # Start oracle for network
|
||||
./scripts/stop.sh # Stop all services
|
||||
```
|
||||
|
||||
## Production Deployment
|
||||
|
||||
For production, run the oracle as a background service:
|
||||
|
||||
### Using systemd (Linux)
|
||||
|
||||
```bash
|
||||
# Copy service file
|
||||
sudo cp deployment/nla-oracle.service /etc/systemd/system/
|
||||
|
||||
# Edit the service file with your paths and config
|
||||
sudo nano /etc/systemd/system/nla-oracle.service
|
||||
|
||||
# Enable and start
|
||||
sudo systemctl enable nla-oracle
|
||||
sudo systemctl start nla-oracle
|
||||
|
||||
# View logs
|
||||
sudo journalctl -u nla-oracle -f
|
||||
```
|
||||
|
||||
### Using nohup (Simple)
|
||||
|
||||
```bash
|
||||
# Start in background
|
||||
nohup ./scripts/start-oracle.sh mainnet > oracle.log 2>&1 &
|
||||
|
||||
# Save PID
|
||||
echo $! > oracle.pid
|
||||
|
||||
# Stop later
|
||||
kill $(cat oracle.pid)
|
||||
```
|
||||
|
||||
### Using screen (Simple)
|
||||
|
||||
```bash
|
||||
# Start screen session
|
||||
screen -S oracle
|
||||
|
||||
# Run oracle
|
||||
./scripts/start-oracle.sh mainnet
|
||||
|
||||
# Detach: Ctrl+A, then D
|
||||
# Reattach: screen -r oracle
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### View Oracle Logs
|
||||
|
||||
```bash
|
||||
# If using systemd
|
||||
sudo journalctl -u nla-oracle -f
|
||||
|
||||
# If using nohup
|
||||
tail -f oracle.log
|
||||
|
||||
# If using Anvil
|
||||
tail -f anvil.log
|
||||
```
|
||||
|
||||
### Check Oracle Status
|
||||
|
||||
```bash
|
||||
# Check if oracle is running
|
||||
ps aux | grep "bun run oracle"
|
||||
|
||||
# Check if Anvil is running
|
||||
lsof -i :8545
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
bun test
|
||||
```
|
||||
|
||||
### Development Mode
|
||||
|
||||
To run:
|
||||
|
||||
```bash
|
||||
|
|
@ -52,3 +232,55 @@ bun run index.ts
|
|||
## Development
|
||||
|
||||
This project was created using `bun init` in bun v1.2.20. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
natural-language-agreements/
|
||||
├── oracle.ts # Oracle CLI application
|
||||
├── deploy.ts # Contract deployment script
|
||||
├── index.ts # Development entry point
|
||||
├── clients/
|
||||
│ └── nla.ts # Natural Language Agreement client
|
||||
├── tests/
|
||||
│ ├── nla.test.ts # Basic tests
|
||||
│ └── nlaOracle.test.ts # Oracle arbitration tests
|
||||
├── deployments/ # Deployment addresses (generated)
|
||||
│ ├── localhost.json
|
||||
│ ├── sepolia.json
|
||||
│ └── mainnet.json
|
||||
├── package.json
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Cannot find module 'alkahest-ts'"
|
||||
- Ensure alkahest is cloned in the parent directory
|
||||
- Run `bun install` in both alkahest and this project
|
||||
|
||||
### "Deployer has no ETH"
|
||||
- Fund your deployer account before running deployment
|
||||
- For testnets, use a faucet
|
||||
|
||||
### "Oracle not detecting arbitration requests"
|
||||
- Verify RPC URL is correct and accessible
|
||||
- Check that EAS contract address matches deployment
|
||||
- Ensure oracle has ETH for gas
|
||||
- Check polling interval (try lowering it)
|
||||
|
||||
### "OpenAI API errors"
|
||||
- Verify API key is valid and active
|
||||
- Check OpenAI usage limits and billing
|
||||
- Ensure model name is correct (e.g., "gpt-4o")
|
||||
|
||||
## Security Notes
|
||||
|
||||
⚠️ **Important Security Considerations:**
|
||||
|
||||
- Never commit your real private keys to version control
|
||||
- Use environment variables or secure secret management for production
|
||||
- The `.env` file is gitignored by default
|
||||
- The example private key in `.env.example` is from Anvil and should NEVER be used in production
|
||||
- Ensure your OpenAI API key is kept secure and not exposed in logs or error messages
|
||||
- Run the oracle in a secure environment with proper access controls
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"network": "localhost",
|
||||
"chainId": 31337,
|
||||
"rpcUrl": "http://localhost:8545",
|
||||
"deployedAt": "2025-12-10T09:13:15.595Z",
|
||||
"deployer": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
||||
"addresses": {
|
||||
"easSchemaRegistry": "0x5fbdb2315678afecb367f032d93f642f64180aa3",
|
||||
"eas": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
|
||||
"trustedOracleArbiter": "0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0",
|
||||
"stringObligation": "0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9",
|
||||
"erc20EscrowObligation": "0xdc64a140aa3e981100a9beca4e685f962f0cf6c9",
|
||||
"erc20PaymentObligation": "0x5fc8d32690cc91d4c39d9d3abcbd16989f875707"
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,11 @@
|
|||
"scripts": {
|
||||
"dev": "bun run index.ts",
|
||||
"start": "bun run index.ts",
|
||||
"test": "bun test ./tests --exclude alkahest-ts/** "
|
||||
"test": "bun test ./tests --exclude alkahest-ts/** ",
|
||||
"setup": "./scripts/dev.sh",
|
||||
"deploy": "./scripts/deploy.sh",
|
||||
"oracle": "./scripts/start-oracle.sh",
|
||||
"stop": "./scripts/stop.sh"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.9.3"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Deploy Alkahest contracts to blockchain
|
||||
# Usage: ./deploy.sh [network] [rpc-url]
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Default values
|
||||
NETWORK=${1:-localhost}
|
||||
RPC_URL=${2:-http://localhost:8545}
|
||||
|
||||
echo -e "${BLUE}🚀 Deploying Alkahest Contracts${NC}\n"
|
||||
|
||||
# Check if deployer private key is set
|
||||
if [ -z "$DEPLOYER_PRIVATE_KEY" ]; then
|
||||
echo -e "${YELLOW}⚠️ DEPLOYER_PRIVATE_KEY not set, using default Anvil key${NC}"
|
||||
export DEPLOYER_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
||||
fi
|
||||
|
||||
# Check if alkahest exists
|
||||
if [ ! -d "../alkahest" ]; then
|
||||
echo -e "${RED}❌ Error: alkahest repository not found in parent directory${NC}"
|
||||
echo "Please clone it first: git clone https://github.com/arkhai-io/alkahest.git"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if contract artifacts exist
|
||||
if [ ! -d "../alkahest/sdks/ts/src/contracts" ]; then
|
||||
echo -e "${RED}❌ Error: Contract artifacts not found${NC}"
|
||||
echo "Expected path: ../alkahest/sdks/ts/src/contracts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✅ Contract artifacts found${NC}\n"
|
||||
|
||||
# Run deployment
|
||||
echo -e "${BLUE}📝 Deploying to ${NETWORK}...${NC}"
|
||||
bun run setups/deploy.ts --network "$NETWORK" --rpc-url "$RPC_URL"
|
||||
|
||||
# Check if deployment was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "\n${GREEN}✨ Deployment complete!${NC}"
|
||||
echo -e "${BLUE}Deployment file saved to: deployments/${NETWORK}.json${NC}\n"
|
||||
|
||||
echo -e "${YELLOW}Next steps:${NC}"
|
||||
echo "1. Start the oracle with:"
|
||||
echo " ./scripts/start-oracle.sh $NETWORK"
|
||||
echo ""
|
||||
echo "2. Or using npm script:"
|
||||
echo " bun run oracle"
|
||||
echo ""
|
||||
echo "3. Or manually:"
|
||||
echo " bun run setups/oracle.ts --deployment ./deployments/${NETWORK}.json"
|
||||
else
|
||||
echo -e "\n${RED}❌ Deployment failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Complete setup and deployment for local development
|
||||
# This script will:
|
||||
# 1. Check prerequisites
|
||||
# 2. Start Anvil
|
||||
# 3. Deploy contracts
|
||||
# 4. Start the oracle
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}════════════════════════════════════════════════════════${NC}"
|
||||
echo -e "${BLUE} Natural Language Agreement Oracle - Quick Setup${NC}"
|
||||
echo -e "${BLUE}════════════════════════════════════════════════════════${NC}\n"
|
||||
|
||||
# Check prerequisites
|
||||
echo -e "${BLUE}📋 Checking prerequisites...${NC}\n"
|
||||
|
||||
# Load .env file if it exists
|
||||
if [ -f ".env" ]; then
|
||||
echo -e "${BLUE}📄 Loading .env file...${NC}"
|
||||
export $(cat .env | grep -v '^#' | xargs)
|
||||
echo -e "${GREEN}✅ Environment variables loaded${NC}"
|
||||
fi
|
||||
|
||||
# Check Bun
|
||||
if ! command -v bun &> /dev/null; then
|
||||
echo -e "${RED}❌ Bun is not installed${NC}"
|
||||
echo "Please install it: https://bun.sh"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Bun installed${NC}"
|
||||
|
||||
# Check Foundry
|
||||
if ! command -v forge &> /dev/null; then
|
||||
echo -e "${RED}❌ Foundry (forge) is not installed${NC}"
|
||||
echo "Please install it: https://book.getfoundry.sh/getting-started/installation"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Foundry installed${NC}"
|
||||
|
||||
# Check Anvil
|
||||
if ! command -v anvil &> /dev/null; then
|
||||
echo -e "${RED}❌ Anvil is not installed${NC}"
|
||||
echo "Please install Foundry: https://book.getfoundry.sh/getting-started/installation"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Anvil installed${NC}"
|
||||
|
||||
# Check alkahest
|
||||
if [ ! -d "../alkahest" ]; then
|
||||
echo -e "${RED}❌ alkahest repository not found${NC}"
|
||||
echo "Please clone it in the parent directory:"
|
||||
echo " cd .. && git clone https://github.com/arkhai-io/alkahest.git"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ alkahest repository found${NC}"
|
||||
|
||||
# Check OpenAI API key
|
||||
if [ -z "$OPENAI_API_KEY" ]; then
|
||||
echo -e "${RED}❌ OPENAI_API_KEY not set${NC}"
|
||||
echo "Please create a .env file with: OPENAI_API_KEY=sk-your-key-here"
|
||||
echo "Or export it: export OPENAI_API_KEY=sk-your-key-here"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ OpenAI API key configured${NC}\n"
|
||||
|
||||
# Install dependencies
|
||||
echo -e "${BLUE}📦 Installing dependencies...${NC}\n"
|
||||
bun install
|
||||
|
||||
# Check if Anvil is already running
|
||||
if lsof -Pi :8545 -sTCP:LISTEN -t >/dev/null ; then
|
||||
echo -e "${YELLOW}⚠️ Anvil is already running on port 8545${NC}"
|
||||
read -p "Do you want to kill it and start fresh? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
pkill -f anvil || true
|
||||
sleep 2
|
||||
else
|
||||
echo -e "${BLUE}Using existing Anvil instance${NC}\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start Anvil in background if not running
|
||||
if ! lsof -Pi :8545 -sTCP:LISTEN -t >/dev/null ; then
|
||||
echo -e "${BLUE}🔨 Starting Anvil...${NC}"
|
||||
anvil > anvil.log 2>&1 &
|
||||
ANVIL_PID=$!
|
||||
echo $ANVIL_PID > .anvil.pid
|
||||
echo -e "${GREEN}✅ Anvil started (PID: $ANVIL_PID)${NC}"
|
||||
echo " Logs: tail -f anvil.log"
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
# Deploy contracts
|
||||
echo -e "\n${BLUE}📝 Deploying contracts...${NC}\n"
|
||||
export DEPLOYER_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
||||
./scripts/deploy.sh localhost http://localhost:8545
|
||||
|
||||
# Start oracle
|
||||
echo -e "\n${BLUE}🚀 Starting oracle...${NC}\n"
|
||||
export ORACLE_PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
|
||||
./scripts/start-oracle.sh localhost
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
echo -e "\n${YELLOW}🛑 Shutting down...${NC}"
|
||||
if [ -f .anvil.pid ]; then
|
||||
ANVIL_PID=$(cat .anvil.pid)
|
||||
kill $ANVIL_PID 2>/dev/null || true
|
||||
rm .anvil.pid
|
||||
echo -e "${GREEN}✅ Anvil stopped${NC}"
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap cleanup SIGINT SIGTERM
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Start the Natural Language Agreement Oracle
|
||||
# Usage: ./start-oracle.sh [network]
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Load .env file if it exists
|
||||
if [ -f ".env" ]; then
|
||||
export $(cat .env | grep -v '^#' | xargs)
|
||||
fi
|
||||
|
||||
# Default network
|
||||
NETWORK=${1:-localhost}
|
||||
DEPLOYMENT_FILE="./deployments/${NETWORK}.json"
|
||||
|
||||
echo -e "${BLUE}🚀 Starting Natural Language Agreement Oracle${NC}\n"
|
||||
|
||||
# Check if deployment file exists
|
||||
if [ ! -f "$DEPLOYMENT_FILE" ]; then
|
||||
echo -e "${RED}❌ Error: Deployment file not found: $DEPLOYMENT_FILE${NC}"
|
||||
echo "Please deploy contracts first:"
|
||||
echo " ./scripts/deploy.sh $NETWORK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if OpenAI API key is set
|
||||
if [ -z "$OPENAI_API_KEY" ]; then
|
||||
echo -e "${RED}❌ Error: OPENAI_API_KEY environment variable is not set${NC}"
|
||||
echo "Please set it:"
|
||||
echo " export OPENAI_API_KEY=sk-your-key-here"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if Oracle private key is set
|
||||
if [ -z "$ORACLE_PRIVATE_KEY" ]; then
|
||||
echo -e "${YELLOW}⚠️ ORACLE_PRIVATE_KEY not set, using default Anvil key${NC}"
|
||||
export ORACLE_PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
|
||||
fi
|
||||
|
||||
# Display configuration
|
||||
echo -e "${GREEN}Configuration:${NC}"
|
||||
echo " Network: $NETWORK"
|
||||
echo " Deployment: $DEPLOYMENT_FILE"
|
||||
echo " Oracle Key: ${ORACLE_PRIVATE_KEY:0:6}...${ORACLE_PRIVATE_KEY: -4}"
|
||||
echo ""
|
||||
|
||||
# Start oracle
|
||||
echo -e "${BLUE}👂 Starting oracle (Press Ctrl+C to stop)...${NC}\n"
|
||||
bun run setups/oracle.ts \
|
||||
--deployment "$DEPLOYMENT_FILE" \
|
||||
--openai-api-key "$OPENAI_API_KEY" \
|
||||
--private-key "$ORACLE_PRIVATE_KEY"
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Stop all running oracle and Anvil processes
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}🛑 Stopping Natural Language Agreement services...${NC}\n"
|
||||
|
||||
# Stop Anvil
|
||||
if [ -f .anvil.pid ]; then
|
||||
ANVIL_PID=$(cat .anvil.pid)
|
||||
if kill -0 $ANVIL_PID 2>/dev/null; then
|
||||
kill $ANVIL_PID
|
||||
echo -e "${GREEN}✅ Stopped Anvil (PID: $ANVIL_PID)${NC}"
|
||||
fi
|
||||
rm .anvil.pid
|
||||
else
|
||||
# Try to kill any running anvil
|
||||
pkill -f anvil && echo -e "${GREEN}✅ Stopped Anvil${NC}" || echo -e "${YELLOW}⚠️ No Anvil process found${NC}"
|
||||
fi
|
||||
|
||||
# Stop oracle
|
||||
pkill -f "bun run oracle" && echo -e "${GREEN}✅ Stopped oracle${NC}" || echo -e "${YELLOW}⚠️ No oracle process found${NC}"
|
||||
|
||||
echo -e "\n${GREEN}✨ Cleanup complete${NC}"
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
#!/usr/bin/env bun
|
||||
/**
|
||||
* Deployment script for Alkahest Natural Language Agreement Oracle
|
||||
*
|
||||
* This script deploys all necessary contracts to a blockchain network
|
||||
* and saves the deployment addresses for use by the oracle CLI.
|
||||
*/
|
||||
|
||||
import { parseArgs } from "util";
|
||||
import { createWalletClient, http, publicActions, parseEther } from "viem";
|
||||
import { privateKeyToAccount } from "viem/accounts";
|
||||
import { mainnet, sepolia, foundry } from "viem/chains";
|
||||
import { writeFileSync, existsSync, mkdirSync } from "fs";
|
||||
import { resolve } from "path";
|
||||
|
||||
// Helper function to display usage
|
||||
function displayHelp() {
|
||||
console.log(`
|
||||
Alkahest Contract Deployment CLI
|
||||
|
||||
Usage:
|
||||
bun deploy.ts [options]
|
||||
|
||||
Options:
|
||||
--network <name> Network to deploy to: mainnet, sepolia, localhost (required)
|
||||
--rpc-url <url> Custom RPC URL (overrides network default)
|
||||
--private-key <key> Deployer's private key (required)
|
||||
--output <path> Output file for deployment addresses (default: ./deployments/<network>.json)
|
||||
--help, -h Display this help message
|
||||
|
||||
Environment Variables (alternative to CLI options):
|
||||
DEPLOYER_PRIVATE_KEY Deployer's private key
|
||||
RPC_URL Custom RPC URL
|
||||
|
||||
Networks:
|
||||
mainnet Ethereum Mainnet
|
||||
sepolia Ethereum Sepolia Testnet
|
||||
localhost Local development (Anvil/Hardhat)
|
||||
|
||||
Examples:
|
||||
# Deploy to local Anvil
|
||||
bun deploy.ts --network localhost --private-key 0x...
|
||||
|
||||
# Deploy to Sepolia
|
||||
bun deploy.ts --network sepolia --private-key 0x... --rpc-url https://sepolia.infura.io/v3/YOUR-KEY
|
||||
|
||||
# Using environment variables
|
||||
export DEPLOYER_PRIVATE_KEY=0x...
|
||||
bun deploy.ts --network localhost
|
||||
`);
|
||||
}
|
||||
|
||||
// Parse command line arguments
|
||||
function parseCliArgs() {
|
||||
const { values } = parseArgs({
|
||||
args: Bun.argv.slice(2),
|
||||
options: {
|
||||
"network": { type: "string" },
|
||||
"rpc-url": { type: "string" },
|
||||
"private-key": { type: "string" },
|
||||
"output": { type: "string" },
|
||||
"help": { type: "boolean", short: "h" },
|
||||
},
|
||||
strict: true,
|
||||
});
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Get chain configuration
|
||||
function getChain(network: string) {
|
||||
switch (network.toLowerCase()) {
|
||||
case "mainnet":
|
||||
return mainnet;
|
||||
case "sepolia":
|
||||
return sepolia;
|
||||
case "localhost":
|
||||
case "local":
|
||||
return foundry;
|
||||
default:
|
||||
throw new Error(`Unknown network: ${network}. Use mainnet, sepolia, or localhost`);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const args = parseCliArgs();
|
||||
|
||||
// Display help if requested
|
||||
if (args.help) {
|
||||
displayHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Get configuration
|
||||
const network = args.network;
|
||||
const privateKey = args["private-key"] || process.env.DEPLOYER_PRIVATE_KEY;
|
||||
let rpcUrl = args["rpc-url"] || process.env.RPC_URL;
|
||||
|
||||
// Validate required parameters
|
||||
if (!network) {
|
||||
console.error("❌ Error: Network is required. Use --network <name>");
|
||||
console.error("Run with --help for usage information.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!privateKey) {
|
||||
console.error("❌ Error: Private key is required. Use --private-key or set DEPLOYER_PRIVATE_KEY");
|
||||
console.error("Run with --help for usage information.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Get chain config
|
||||
const chain = getChain(network);
|
||||
|
||||
// Set default RPC URL if not provided
|
||||
if (!rpcUrl) {
|
||||
if (network === "localhost") {
|
||||
rpcUrl = "http://localhost:8545";
|
||||
} else {
|
||||
console.error("❌ Error: RPC URL is required for non-localhost networks. Use --rpc-url");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("🚀 Starting Alkahest Contract Deployment\n");
|
||||
console.log("Configuration:");
|
||||
console.log(` 🌐 Network: ${network}`);
|
||||
console.log(` 📡 RPC URL: ${rpcUrl}`);
|
||||
console.log(` 🔑 Deployer: ${privateKey.slice(0, 6)}...${privateKey.slice(-4)}\n`);
|
||||
|
||||
// Create deployer account and client
|
||||
const account = privateKeyToAccount(privateKey as `0x${string}`);
|
||||
const client = createWalletClient({
|
||||
account,
|
||||
chain,
|
||||
transport: http(rpcUrl),
|
||||
}).extend(publicActions);
|
||||
|
||||
console.log(`✅ Deployer address: ${account.address}\n`);
|
||||
|
||||
// Check balance
|
||||
const balance = await client.getBalance({ address: account.address });
|
||||
console.log(`💰 Deployer balance: ${parseFloat((balance / 10n ** 18n).toString()).toFixed(4)} ETH\n`);
|
||||
|
||||
if (balance === 0n) {
|
||||
console.error("❌ Error: Deployer has no ETH. Please fund the account first.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Import contract artifacts from alkahest
|
||||
console.log("📦 Loading contract artifacts...\n");
|
||||
|
||||
// This requires alkahest to be properly set up
|
||||
const alkahestPath = "../../alkahest/sdks/ts";
|
||||
const contractsPath = `${alkahestPath}/src/contracts`;
|
||||
|
||||
// Import necessary artifacts
|
||||
const EAS = await import(`${alkahestPath}/tests/fixtures/EAS.json`);
|
||||
const SchemaRegistry = await import(`${alkahestPath}/tests/fixtures/SchemaRegistry.json`);
|
||||
const TrustedOracleArbiter = await import(`${contractsPath}/TrustedOracleArbiter.json`);
|
||||
const StringObligation = await import(`${contractsPath}/StringObligation.json`);
|
||||
const ERC20EscrowObligation = await import(`${contractsPath}/ERC20EscrowObligation.json`);
|
||||
const ERC20PaymentObligation = await import(`${contractsPath}/ERC20PaymentObligation.json`);
|
||||
|
||||
console.log("✅ Contract artifacts loaded\n");
|
||||
|
||||
// Deployment addresses
|
||||
const addresses: Record<string, string> = {};
|
||||
|
||||
// Helper to deploy contracts
|
||||
async function deployContract(
|
||||
name: string,
|
||||
abi: any,
|
||||
bytecode: string,
|
||||
args: any[] = []
|
||||
): Promise<string> {
|
||||
console.log(`📝 Deploying ${name}...`);
|
||||
|
||||
const hash = await client.deployContract({
|
||||
abi,
|
||||
bytecode: bytecode as `0x${string}`,
|
||||
args,
|
||||
});
|
||||
|
||||
console.log(` Transaction: ${hash}`);
|
||||
const receipt = await client.waitForTransactionReceipt({ hash });
|
||||
|
||||
if (!receipt.contractAddress) {
|
||||
throw new Error(`Failed to deploy ${name}`);
|
||||
}
|
||||
|
||||
console.log(` ✅ Deployed at: ${receipt.contractAddress}\n`);
|
||||
return receipt.contractAddress;
|
||||
}
|
||||
|
||||
// Deploy core contracts
|
||||
console.log("🏗️ Deploying core contracts...\n");
|
||||
|
||||
addresses.easSchemaRegistry = await deployContract(
|
||||
"EAS Schema Registry",
|
||||
SchemaRegistry.abi,
|
||||
SchemaRegistry.bytecode.object
|
||||
);
|
||||
|
||||
addresses.eas = await deployContract(
|
||||
"EAS",
|
||||
EAS.abi,
|
||||
EAS.bytecode.object,
|
||||
[addresses.easSchemaRegistry]
|
||||
);
|
||||
|
||||
// Deploy arbiters
|
||||
console.log("⚖️ Deploying arbiters...\n");
|
||||
|
||||
addresses.trustedOracleArbiter = await deployContract(
|
||||
"Trusted Oracle Arbiter",
|
||||
TrustedOracleArbiter.abi,
|
||||
TrustedOracleArbiter.bytecode.object,
|
||||
[addresses.eas]
|
||||
);
|
||||
|
||||
// Deploy obligations
|
||||
console.log("📋 Deploying obligations...\n");
|
||||
|
||||
addresses.stringObligation = await deployContract(
|
||||
"String Obligation",
|
||||
StringObligation.abi,
|
||||
StringObligation.bytecode.object,
|
||||
[addresses.eas, addresses.easSchemaRegistry]
|
||||
);
|
||||
|
||||
addresses.erc20EscrowObligation = await deployContract(
|
||||
"ERC20 Escrow Obligation",
|
||||
ERC20EscrowObligation.abi,
|
||||
ERC20EscrowObligation.bytecode.object,
|
||||
[addresses.eas, addresses.easSchemaRegistry]
|
||||
);
|
||||
|
||||
addresses.erc20PaymentObligation = await deployContract(
|
||||
"ERC20 Payment Obligation",
|
||||
ERC20PaymentObligation.abi,
|
||||
ERC20PaymentObligation.bytecode.object,
|
||||
[addresses.eas, addresses.easSchemaRegistry]
|
||||
);
|
||||
|
||||
// Save deployment addresses
|
||||
const outputPath = args.output || resolve(`./deployments/${network}.json`);
|
||||
const outputDir = resolve(outputPath, "..");
|
||||
|
||||
if (!existsSync(outputDir)) {
|
||||
mkdirSync(outputDir, { recursive: true });
|
||||
}
|
||||
|
||||
const deployment = {
|
||||
network,
|
||||
chainId: chain.id,
|
||||
rpcUrl,
|
||||
deployedAt: new Date().toISOString(),
|
||||
deployer: account.address,
|
||||
addresses,
|
||||
};
|
||||
|
||||
writeFileSync(outputPath, JSON.stringify(deployment, null, 2));
|
||||
|
||||
console.log("✨ Deployment complete!\n");
|
||||
console.log("📄 Deployment details saved to:", outputPath);
|
||||
console.log("\n📋 Deployed Addresses:");
|
||||
Object.entries(addresses).forEach(([name, address]) => {
|
||||
console.log(` ${name}: ${address}`);
|
||||
});
|
||||
|
||||
console.log("\n🎯 Next steps:");
|
||||
console.log("1. Save the deployment file for your records");
|
||||
console.log("2. Update your oracle configuration with the EAS contract address:");
|
||||
console.log(` export EAS_CONTRACT_ADDRESS=${addresses.eas}`);
|
||||
console.log("3. Start the oracle:");
|
||||
console.log(` bun run oracle -- --rpc-url ${rpcUrl} --eas-contract ${addresses.eas}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ Deployment failed:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the deployment
|
||||
main();
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
#!/usr/bin/env bun
|
||||
import { parseArgs } from "util";
|
||||
import { parseAbiParameters } from "viem";
|
||||
import { makeLLMClient } from "../clients/nla";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import { resolve } from "path";
|
||||
|
||||
// Helper function to display usage
|
||||
function displayHelp() {
|
||||
console.log(`
|
||||
Natural Language Agreement Oracle CLI
|
||||
|
||||
Usage:
|
||||
bun oracle.ts [options]
|
||||
|
||||
Options:
|
||||
--rpc-url <url> RPC URL for the blockchain network (required)
|
||||
--private-key <key> Private key of the oracle operator (required)
|
||||
--openai-api-key <key> OpenAI API key (required)
|
||||
--eas-contract <address> EAS contract address (optional)
|
||||
--deployment <file> Load addresses from deployment file (optional)
|
||||
--polling-interval <ms> Polling interval in milliseconds (default: 5000)
|
||||
--help, -h Display this help message
|
||||
|
||||
Environment Variables (alternative to CLI options):
|
||||
RPC_URL RPC URL for the blockchain network
|
||||
ORACLE_PRIVATE_KEY Private key of the oracle operator
|
||||
OPENAI_API_KEY OpenAI API key
|
||||
EAS_CONTRACT_ADDRESS EAS contract address
|
||||
|
||||
Examples:
|
||||
# Using command line options
|
||||
bun oracle.ts --rpc-url http://localhost:8545 --private-key 0x... --openai-api-key sk-...
|
||||
|
||||
# Using deployment file
|
||||
bun oracle.ts --deployment ./deployments/localhost.json --private-key 0x... --openai-api-key sk-...
|
||||
|
||||
# Using environment variables
|
||||
export OPENAI_API_KEY=sk-...
|
||||
export RPC_URL=http://localhost:8545
|
||||
export ORACLE_PRIVATE_KEY=0x...
|
||||
bun oracle.ts
|
||||
`);
|
||||
}
|
||||
|
||||
// Parse command line arguments
|
||||
function parseCliArgs() {
|
||||
const { values } = parseArgs({
|
||||
args: Bun.argv.slice(2),
|
||||
options: {
|
||||
"rpc-url": { type: "string" },
|
||||
"private-key": { type: "string" },
|
||||
"openai-api-key": { type: "string" },
|
||||
"eas-contract": { type: "string" },
|
||||
"deployment": { type: "string" },
|
||||
"polling-interval": { type: "string" },
|
||||
"help": { type: "boolean", short: "h" },
|
||||
},
|
||||
strict: true,
|
||||
});
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Load deployment file
|
||||
function loadDeployment(filePath: string) {
|
||||
if (!existsSync(filePath)) {
|
||||
throw new Error(`Deployment file not found: ${filePath}`);
|
||||
}
|
||||
|
||||
const content = readFileSync(filePath, "utf-8");
|
||||
return JSON.parse(content);
|
||||
}
|
||||
|
||||
// Main function
|
||||
async function main() {
|
||||
try {
|
||||
const args = parseCliArgs();
|
||||
|
||||
// Display help if requested
|
||||
if (args.help) {
|
||||
displayHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
let rpcUrl = args["rpc-url"] || process.env.RPC_URL;
|
||||
let easContract = args["eas-contract"] || process.env.EAS_CONTRACT_ADDRESS;
|
||||
let deploymentAddresses = null;
|
||||
|
||||
// Load deployment file if provided
|
||||
if (args.deployment) {
|
||||
console.log(`📄 Loading deployment from: ${args.deployment}\n`);
|
||||
const deployment = loadDeployment(args.deployment);
|
||||
deploymentAddresses = deployment.addresses;
|
||||
|
||||
if (!rpcUrl) {
|
||||
rpcUrl = deployment.rpcUrl;
|
||||
}
|
||||
if (!easContract) {
|
||||
easContract = deployment.addresses.eas;
|
||||
}
|
||||
|
||||
console.log(`✅ Loaded deployment (${deployment.network})\n`);
|
||||
}
|
||||
|
||||
const privateKey = args["private-key"] || process.env.ORACLE_PRIVATE_KEY;
|
||||
const openaiApiKey = args["openai-api-key"] || process.env.OPENAI_API_KEY;
|
||||
const pollingInterval = parseInt(args["polling-interval"] || "5000");
|
||||
|
||||
// Validate required parameters
|
||||
if (!rpcUrl) {
|
||||
console.error("❌ Error: RPC URL is required. Use --rpc-url or set RPC_URL environment variable.");
|
||||
console.error("Run with --help for usage information.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!privateKey) {
|
||||
console.error("❌ Error: Private key is required. Use --private-key or set ORACLE_PRIVATE_KEY environment variable.");
|
||||
console.error("Run with --help for usage information.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!openaiApiKey) {
|
||||
console.error("❌ Error: OpenAI API key is required. Use --openai-api-key or set OPENAI_API_KEY environment variable.");
|
||||
console.error("Run with --help for usage information.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Import alkahest client
|
||||
const { makeClient } = await import("../../alkahest/sdks/ts/src/index.ts");
|
||||
const { createWalletClient, http, publicActions } = await import("viem");
|
||||
const { privateKeyToAccount } = await import("viem/accounts");
|
||||
const { foundry } = await import("viem/chains");
|
||||
|
||||
console.log("🚀 Starting Natural Language Agreement Oracle...\n");
|
||||
console.log("Configuration:");
|
||||
console.log(` 📡 RPC URL: ${rpcUrl}`);
|
||||
console.log(` 🔑 Oracle Key: ${privateKey.slice(0, 6)}...${privateKey.slice(-4)}`);
|
||||
console.log(` 🤖 AI Provider: OpenAI`);
|
||||
if (easContract) {
|
||||
console.log(` 📝 EAS Contract: ${easContract}`);
|
||||
}
|
||||
console.log(` ⏱️ Polling Interval: ${pollingInterval}ms\n`);
|
||||
|
||||
// Create wallet client
|
||||
const account = privateKeyToAccount(privateKey as `0x${string}`);
|
||||
const walletClient = createWalletClient({
|
||||
account,
|
||||
chain: foundry,
|
||||
transport: http(rpcUrl),
|
||||
}).extend(publicActions) as any;
|
||||
|
||||
// Create alkahest client
|
||||
const client = makeClient(walletClient, deploymentAddresses || { eas: easContract });
|
||||
|
||||
console.log(`✅ Oracle initialized with address: ${account.address}\n`);
|
||||
|
||||
// Create LLM client
|
||||
const llmClient = client.extend(() => ({
|
||||
llm: makeLLMClient([]),
|
||||
}));
|
||||
|
||||
llmClient.llm.addProvider({
|
||||
providerName: "OpenAI",
|
||||
apiKey: openaiApiKey,
|
||||
});
|
||||
|
||||
console.log("🎯 LLM Arbitrator configured and ready\n");
|
||||
console.log("👂 Listening for arbitration requests...\n");
|
||||
|
||||
// Define the obligation ABI
|
||||
const obligationAbi = parseAbiParameters("(string item)");
|
||||
|
||||
// Start listening and arbitrating
|
||||
const { unwatch } = await client.oracle.listenAndArbitrate(
|
||||
async (attestation: any) => {
|
||||
console.log(`\n📨 New arbitration request received!`);
|
||||
console.log(` Attestation UID: ${attestation.uid}`);
|
||||
|
||||
try {
|
||||
// Extract obligation data
|
||||
const obligation = client.extractObligationData(
|
||||
obligationAbi,
|
||||
attestation,
|
||||
);
|
||||
console.log(` Obligation: "${obligation[0].item}"`);
|
||||
|
||||
// Get demand data
|
||||
const [, demand] = await client.getEscrowAndDemand(
|
||||
llmClient.llm.LLMAbi,
|
||||
attestation,
|
||||
);
|
||||
console.log(` Demand: "${demand[0].demand}"`);
|
||||
console.log(` Model: ${demand[0].arbitrationModel}`);
|
||||
|
||||
// Perform arbitration using LLM
|
||||
console.log(` 🤔 Arbitrating with AI...`);
|
||||
const result = await llmClient.llm.arbitrate(
|
||||
demand[0],
|
||||
obligation[0].item
|
||||
);
|
||||
|
||||
console.log(` ✨ Arbitration result: ${result ? "✅ APPROVED" : "❌ REJECTED"}`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(` ❌ Error during arbitration:`, error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
{
|
||||
onAfterArbitrate: async (decision: any) => {
|
||||
console.log(` 📝 Arbitration decision recorded on-chain`);
|
||||
console.log(` Decision UID: ${decision.attestation.uid}`);
|
||||
console.log(` Result: ${decision.decision ? "✅ Fulfilled" : "❌ Not Fulfilled"}\n`);
|
||||
},
|
||||
pollingInterval,
|
||||
},
|
||||
);
|
||||
|
||||
console.log("✨ Oracle is now running. Press Ctrl+C to stop.\n");
|
||||
|
||||
// Handle graceful shutdown
|
||||
const shutdown = async () => {
|
||||
console.log("\n\n🛑 Shutting down oracle...");
|
||||
unwatch();
|
||||
console.log("👋 Oracle stopped gracefully");
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
process.on("SIGINT", shutdown);
|
||||
process.on("SIGTERM", shutdown);
|
||||
|
||||
// Keep the process alive
|
||||
await new Promise(() => { });
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ Fatal error:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the CLI
|
||||
main();
|
||||
Loading…
Reference in New Issue