Merge pull request #7 from arkhai-io/refactor

Refactor
This commit is contained in:
thanhngoc541 2026-02-02 16:50:26 +07:00 committed by GitHub
commit d15bcecd1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 51 additions and 207 deletions

View File

@ -4,11 +4,11 @@
# DEPLOYMENT CONFIGURATION
# ================================
# Deployer's private key (used for contract deployment)
# Private key (used for deployment and oracle operations)
# 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
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# ================================
# ORACLE CONFIGURATION
@ -21,12 +21,6 @@ DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf
# 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...

View File

@ -1,173 +0,0 @@
# Installing NLA CLI Globally
## Prerequisites
- Node.js >= 18.0.0
- npm or yarn or pnpm
- A blockchain node (local Anvil or remote RPC URL)
- At least one LLM provider API key (OpenAI, Anthropic, or OpenRouter)
## Installation
### Global Installation (Recommended)
Install the NLA CLI globally to use it from anywhere:
```bash
npm install -g nla
```
Or with yarn:
```bash
yarn global add nla
```
Or with pnpm:
```bash
pnpm add -g nla
```
### Verify Installation
```bash
nla --help
```
## Configuration
Create a `.env` file in your project directory:
```bash
# Copy the example environment file
cp node_modules/nla/.env.example .env
# Edit with your configuration
nano .env
```
Required environment variables:
```bash
# At least one LLM provider API key
OPENAI_API_KEY=sk-...
# OR
ANTHROPIC_API_KEY=sk-ant-...
# OR
OPENROUTER_API_KEY=sk-or-...
# Oracle configuration
ORACLE_PRIVATE_KEY=0x...
RPC_URL=http://localhost:8545
# Optional: For enhanced search
PERPLEXITY_API_KEY=pplx-...
```
## Quick Start
### 1. Start Development Environment
```bash
nla dev
```
This will:
- Start Anvil (local blockchain)
- Deploy all contracts
- Start the oracle
### 2. Create an Escrow
```bash
nla escrow:create \
--demand "The sky is blue" \
--amount 10 \
--token 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 \
--oracle 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
```
### 3. Fulfill an Escrow
```bash
nla escrow:fulfill \
--escrow-uid 0x... \
--fulfillment "The sky appears blue today" \
--oracle 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
```
### 4. Collect Payment
```bash
nla escrow:collect \
--escrow-uid 0x... \
--fulfillment-uid 0x...
```
## Uninstallation
```bash
npm uninstall -g nla
```
## Development
If you want to contribute or modify the CLI:
```bash
# Clone the repository
git clone https://github.com/arkhai-io/natural-language-agreements.git
cd natural-language-agreements
# Install dependencies
npm install
# Build
npm run build
# Link locally
npm link
```
## Troubleshooting
### Command not found after installation
Make sure your npm global bin directory is in your PATH:
```bash
# Check npm global bin path
npm bin -g
# Add to PATH (add to ~/.bashrc or ~/.zshrc)
export PATH="$(npm bin -g):$PATH"
```
### Permission errors on Linux/Mac
If you get permission errors, either:
1. Use a Node version manager (recommended):
```bash
# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Install and use Node
nvm install 18
nvm use 18
# Now install without sudo
npm install -g nla
```
2. Or configure npm to use a different directory:
```bash
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
```
## Support
For issues and questions:
- GitHub: https://github.com/arkhai-io/natural-language-agreements/issues
- Documentation: https://github.com/arkhai-io/natural-language-agreements

View File

@ -179,8 +179,7 @@ nla escrow:collect \
```bash
# 1. Get Sepolia ETH from faucet
# 2. Set your keys
export DEPLOYER_PRIVATE_KEY=0x...
export ORACLE_PRIVATE_KEY=0x...
export PRIVATE_KEY=0x...
export OPENAI_API_KEY=sk-...
# 3. Deploy
@ -194,8 +193,7 @@ nla start-oracle sepolia
```bash
# ⚠️ PRODUCTION - Be careful!
export DEPLOYER_PRIVATE_KEY=0x...
export ORACLE_PRIVATE_KEY=0x...
export PRIVATE_KEY=0x...
export OPENAI_API_KEY=sk-...
# Deploy

View File

@ -159,7 +159,7 @@ nla start-oracle mainnet # Start oracle for mainnet
Starts the oracle service that listens for arbitration requests. Requires:
- `OPENAI_API_KEY` environment variable
- `ORACLE_PRIVATE_KEY` environment variable (defaults to Anvil account #1)
- `PRIVATE_KEY` environment variable (defaults to Anvil account #1)
- Deployment file at `cli/deployments/{network}.json`
#### Stop Services

View File

@ -1,7 +1,7 @@
import { spawn, spawnSync } from "child_process";
import { existsSync, readFileSync, writeFileSync, createWriteStream, unlinkSync } from "fs";
import { join } from "path";
import { getCurrentEnvironment, setCurrentEnvironment } from "../utils.js";
import { getCurrentEnvironment, setCurrentEnvironment, getPrivateKey } from "../utils.js";
// Colors for console output
const colors = {
@ -67,7 +67,7 @@ function isPortInUse(port: number): boolean {
}
// Dev command - Start complete development environment
export async function runDevCommand(cliDir: string, envPath?: string) {
export async function runDevCommand(cliDir: string, envPath?: string, cliPrivateKey?: string) {
console.log(`${colors.blue}════════════════════════════════════════════════════════${colors.reset}`);
console.log(`${colors.blue} Natural Language Agreement Oracle - Quick Setup${colors.reset}`);
console.log(`${colors.blue}════════════════════════════════════════════════════════${colors.reset}\n`);
@ -86,6 +86,9 @@ export async function runDevCommand(cliDir: string, envPath?: string) {
loadEnvFile(envPath);
console.log('');
// Get private key from CLI arg, config, or env (same pattern as other commands)
const privateKey = cliPrivateKey || getPrivateKey();
// Check prerequisites
console.log(`${colors.blue}📋 Checking prerequisites...${colors.reset}\n`);
@ -166,7 +169,11 @@ export async function runDevCommand(cliDir: string, envPath?: string) {
// Deploy contracts
console.log(`\n${colors.blue}📝 Deploying contracts...${colors.reset}\n`);
const deployScript = join(cliDir, 'server', 'deploy.js');
const deployResult = spawnSync('bun', ['run', deployScript, '--network', 'localhost', '--rpc-url', 'http://localhost:8545'], {
const deployArgs = ['run', deployScript, '--network', 'localhost', '--rpc-url', 'http://localhost:8545'];
if (privateKey) {
deployArgs.push('--private-key', privateKey);
}
const deployResult = spawnSync('bun', deployArgs, {
stdio: 'inherit',
cwd: process.cwd()
});
@ -185,7 +192,12 @@ export async function runDevCommand(cliDir: string, envPath?: string) {
const distPath = join(cliDir, 'deployments', 'devnet.json');
const deploymentFile = existsSync(sourcePath) ? sourcePath : distPath;
const oracleProcess = spawn('bun', ['run', oracleScript, '--deployment', deploymentFile], {
const oracleArgs = ['run', oracleScript, '--deployment', deploymentFile];
if (privateKey) {
oracleArgs.push('--private-key', privateKey);
}
const oracleProcess = spawn('bun', oracleArgs, {
stdio: 'inherit',
cwd: process.cwd()
});

View File

@ -135,6 +135,7 @@ function parseCliArgs() {
"arbitration-prompt": { type: "string" },
"env": { type: "string" },
"environment": { type: "string" },
"help": { type: "boolean", short: "h" },
},
strict: command !== "switch" && command !== "network", // Allow positional args for switch command
allowPositionals: command === "switch" || command === "network",
@ -164,7 +165,7 @@ async function main() {
// Handle dev and stop commands
if (command === "dev") {
await runDevCommand(__dirname, args.env as string | undefined);
await runDevCommand(__dirname, args.env as string | undefined, args["private-key"] as string | undefined);
return;
}

View File

@ -13,6 +13,7 @@ import { mainnet, sepolia, baseSepolia, foundry } from "viem/chains";
import { writeFileSync, existsSync, mkdirSync } from "fs";
import { resolve } from "path";
import { fixtures, contracts } from "alkahest-ts";
import { getPrivateKey } from "../utils.js";
// Helper function to display usage
function displayHelp() {
@ -30,7 +31,7 @@ Options:
--help, -h Display this help message
Environment Variables (alternative to CLI options):
DEPLOYER_PRIVATE_KEY Deployer's private key
PRIVATE_KEY Deployer's private key
RPC_URL Custom RPC URL
Networks:
@ -47,7 +48,7 @@ Examples:
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...
export PRIVATE_KEY=0x...
bun deploy.ts --network localhost
`);
}
@ -98,7 +99,7 @@ async function main() {
// Get configuration
const network = args.network;
const privateKey = args["private-key"] || process.env.DEPLOYER_PRIVATE_KEY;
const privateKey = args["private-key"] || getPrivateKey();
let rpcUrl = args["rpc-url"] || process.env.RPC_URL;
// Validate required parameters
@ -109,8 +110,12 @@ async function main() {
}
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.");
console.error("❌ Error: Private key is required.");
console.error("\n💡 You can either:");
console.error(" 1. Set it globally: nla wallet:set --private-key <your-key>");
console.error(" 2. Use for this command only: --private-key <your-key>");
console.error(" 3. Set PRIVATE_KEY environment variable");
console.error("\nRun with --help for usage information.");
process.exit(1);
}

View File

@ -33,6 +33,7 @@ Usage:
Options:
--private-key <key> Private key of the oracle operator (optional, loaded from .env)
--rpc-url <url> RPC URL to connect to (optional, overrides deployment file)
--openai-api-key <key> OpenAI API key (optional, loaded from .env)
--anthropic-api-key <key> Anthropic API key (optional, loaded from .env)
--openrouter-api-key <key> OpenRouter API key (optional, loaded from .env)
@ -43,7 +44,7 @@ Options:
--help, -h Display this help message
Environment Variables (from .env file or environment):
ORACLE_PRIVATE_KEY Private key of the oracle operator
PRIVATE_KEY Private key of the oracle operator
OPENAI_API_KEY OpenAI API key
ANTHROPIC_API_KEY Anthropic API key
OPENROUTER_API_KEY OpenRouter API key
@ -62,11 +63,14 @@ Examples:
# Using specific deployment file
bun oracle.ts --deployment ./deployments/sepolia.json
# Using custom RPC URL
bun oracle.ts --rpc-url https://eth-mainnet.g.alchemy.com/v2/YOUR-KEY
# Mix of .env and command-line parameters
bun oracle.ts --openai-api-key sk-... --env .env.local
Example .env file:
ORACLE_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
OPENROUTER_API_KEY=sk-or-...
@ -80,6 +84,7 @@ function parseCliArgs() {
args: process.argv.slice(2),
options: {
"private-key": { type: "string" },
"rpc-url": { type: "string" },
"openai-api-key": { type: "string" },
"anthropic-api-key": { type: "string" },
"openrouter-api-key": { type: "string" },
@ -133,6 +138,7 @@ async function main() {
console.log(`✅ Loaded deployment (${deployment.network})\n`);
const privateKey = args["private-key"] || getPrivateKey();
const rpcUrl = args["rpc-url"] || deployment.rpcUrl;
const openaiApiKey = args["openai-api-key"] || process.env.OPENAI_API_KEY;
const anthropicApiKey = args["anthropic-api-key"] || process.env.ANTHROPIC_API_KEY;
const openrouterApiKey = args["openrouter-api-key"] || process.env.OPENROUTER_API_KEY;
@ -140,10 +146,12 @@ async function main() {
const pollingInterval = parseInt(args["polling-interval"] || "5000");
// Validate required parameters
if (!deployment?.rpcUrl) {
console.error("❌ Error: RPC URL not found in deployment file.");
console.error(" Current environment:", getCurrentEnvironment());
console.error(" Make sure the deployment file exists for your current network.");
if (!rpcUrl) {
console.error("❌ Error: RPC URL not found.");
console.error(" Please either:");
console.error(" 1. Use --rpc-url <url>");
console.error(" 2. Use a deployment file with rpcUrl set");
console.error(" 3. Set RPC_URL environment variable");
console.error("Run with --help for usage information.");
process.exit(1);
}
@ -153,8 +161,7 @@ async function main() {
console.error("\n💡 You can either:");
console.error(" 1. Set it globally: nla wallet:set --private-key <your-key>");
console.error(" 2. Use for this command only: --private-key <your-key>");
console.error(" 3. Set ORACLE_PRIVATE_KEY in .env file");
console.error(" 4. Set PRIVATE_KEY environment variable");
console.error(" 3. Set PRIVATE_KEY environment variable");
console.error("\nRun with --help for usage information.");
process.exit(1);
}
@ -172,7 +179,7 @@ async function main() {
console.log("🚀 Starting Natural Language Agreement Oracle...\n");
console.log("Configuration:");
console.log(` 📡 RPC URL: ${deployment.rpcUrl}`);
console.log(` 📡 RPC URL: ${rpcUrl}`);
console.log(` 🔑 Oracle Key: ${privateKey.slice(0, 6)}...${privateKey.slice(-4)}`);
// Show available providers
@ -197,7 +204,7 @@ async function main() {
const walletClient = createWalletClient({
account,
chain,
transport: http(deployment.rpcUrl),
transport: http(rpcUrl),
}).extend(publicActions) as any;

View File

@ -1,6 +1,6 @@
{
"name": "nla",
"version": "1.0.5",
"version": "1.0.8",
"description": "Natural Language Agreement Oracle - CLI for creating and managing blockchain agreements using natural language",
"type": "module",
"private": false,