Skip to content

akash-network/hermes

Repository files navigation

Hermes replayer of Pyth price feed into Akash

Automatic price feed updater for Akash Network oracle contracts using Pyth Network's Hermes API.

📁 Project Structure

hermes-client/
├── src/
│   ├── hermes-client.ts       # Main client implementation
│   └── cli.ts                 # CLI tool
├── package.json               # Node.js dependencies
├── tsconfig.json              # TypeScript configuration
├── .env.example               # Environment variables template
├── Dockerfile                 # Docker image
├── docker-compose.yml         # Docker Compose setup
├── hermes-client.service      # Systemd service file
└── README.md                  # This file

🚀 Quick Start

1. Install Dependencies

npm install

2. Configure Environment

cp .env.example .env

Edit .env:

RPC_ENDPOINT=https://rpc.akashnet.net:443
CONTRACT_ADDRESS=akash1your_contract_address
MNEMONIC="your twelve or twenty four word mnemonic"

3. Run

# Build TypeScript
npm run build

# Run one-time update
npm run cli:update

# Query current price
npm run cli:query

# Start daemon (continuous updates)
npm run cli:daemon

📋 Available Commands

NPM Scripts

npm run build          # Compile TypeScript to JavaScript
npm run start          # Start the client daemon
npm run dev            # Run in development mode
npm run cli            # Run CLI tool
npm run cli:update     # Update price once
npm run cli:query      # Query current price
npm run cli:status     # Show client status
npm run cli:daemon     # Run continuous updates

CLI Usage

# After building
node dist/cli.js update    # Update price once
node dist/cli.js query     # Query current price
node dist/cli.js status    # Show status
node dist/cli.js daemon    # Run daemon

🐳 Docker Deployment

Option 1: Docker Compose (Recommended)

# Configure .env first
cp .env.example .env
# Edit .env with your settings

# Start
docker-compose up -d

# View logs
docker-compose logs -f hermes-client

# Stop
docker-compose down

Option 2: Docker Build & Run

# Build image
docker build -t akash-hermes-client .

# Run container
docker run -d \
  --name hermes-client \
  --env-file .env \
  --restart unless-stopped \
  akash-hermes-client

# View logs
docker logs -f hermes-client

🔄 Systemd Service (Linux Production)

# 1. Build project
npm run build

# 2. Copy to /opt
sudo mkdir -p /opt/hermes-client
sudo cp -r dist package.json .env /opt/hermes-client/
cd /opt/hermes-client
sudo npm ci --production

# 3. Install systemd service
sudo cp hermes-client.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable hermes-client
sudo systemctl start hermes-client

# 4. Check status
sudo systemctl status hermes-client
sudo journalctl -u hermes-client -f

📊 Monitoring

Check Logs

# Docker Compose
docker-compose logs -f

# Docker
docker logs -f hermes-client

# Systemd
sudo journalctl -u hermes-client -f

Query Contract

# Check current price
akash query wasm contract-state smart $CONTRACT_ADDRESS '{"get_price":{}}'

# Check configuration
akash query wasm contract-state smart $CONTRACT_ADDRESS '{"get_config":{}}'

⚙️ Configuration

Environment Variables

Variable Required Default Description
RPC_ENDPOINT Yes - Akash RPC endpoint
CONTRACT_ADDRESS Yes - Oracle contract address
WALLET_SECRET Yes - Either privateKey:<private key in hex format> or mnemonic:<12/24 words>
HERMES_ENDPOINT No https://hermes.pyth.network Pyth Hermes API
PRICE_DEVIATION_TOLERANCE No 0 absolute or percentage value for price deviations which should be ignored (e.g., 100 or 10%)
UPDATE_INTERVAL_MS No 300000 Update interval (5 min)
GAS_PRICE No 0.025uakt Gas price
DENOM No uakt Token denomination
HEALTHCHECK_PORT No 3000 healthcheck server port
OTEL_RESOURCE_ATTRIBUTES No additional attributes attached to all metrics (e.g., service.name=hermes,service.version=1.1.0,deployment.environment=production)

Instrumentation

This service exposes a /health endpoint that can be polled periodically to check whether the service is healthy. It also exposes a /metrics endpoint for collecting service metrics in Prometheus format. The /metrics endpoint is only available when the service is run with instrumentation enabled.

Instrumentation is powered by OpenTelemetry and collects Node.js runtime metrics (e.g., event loop delay, GC, active handles) with a 5-second monitoring precision. The following resource detectors enrich metrics with contextual metadata:

  • processDetector — process-level attributes such as PID, executable name, and command-line arguments
  • envDetector — resource attributes from the OTEL_RESOURCE_ATTRIBUTES environment variable. This variable allows to set extra labels (e.g., environment, service version.)
  • hostDetector — host information such as hostname
  • containerDetector — container ID from the cgroup file when running inside a container (e.g., Docker)

To run the service with instrumentation enabled:

# in dev mode
node --experimental-strip-types --watch --env-file=.env --import ./src/instrumentation.ts src/cli.ts daemon

# compiled
node --env-file=.env --import ./dist/instrumentation.js dist/cli.js daemon

Update Frequency

Change update interval in .env:

UPDATE_INTERVAL_MS=300000   # 5 minutes (default)
UPDATE_INTERVAL_MS=180000   # 3 minutes
UPDATE_INTERVAL_MS=600000   # 10 minutes

💡 How It Works

Workflow

1. Initialize client
   - Load configuration
   - Create wallet from mnemonic
   - Connect to Akash RPC
   - Query contract for price_feed_id
         ↓
2. Fetch price from Pyth Hermes
   GET https://hermes.pyth.network/v2/updates/price/latest?ids={price_feed_id}
         ↓
3. Query current price from contract
         ↓
4. Compare publish times
   - If new data → Update contract
   - If same/old → Skip update
         ↓
5. Wait for next interval
   - Repeat from step 2

Smart Update Logic

The client only submits transactions when:

  • ✅ New price data is available (newer publish_time)
  • ✅ Wallet has sufficient balance
  • ✅ Price passes validation (non-zero, reasonable confidence)

This minimizes transaction costs and blockchain load.

💰 Cost Estimation

Per Update

Gas cost:   150,000 gas × 0.025 uakt/gas = 3,750 uakt
Update fee: 1,000 uakt (example, set in contract)
Total:      ~4,750 uakt per update

Monthly Cost (5-minute updates)

Updates per day:    288
Updates per month:  8,640
Monthly cost:       8,640 × 4,750 uakt = 41.04 AKT

Reduce Costs

Increase update interval to reduce costs:

UPDATE_INTERVAL_MS=600000   # 10 min → 50% cost savings
UPDATE_INTERVAL_MS=900000   # 15 min → 67% cost savings

🔒 Security

Wallet Security

Use dedicated wallet - Create separate wallet for oracle updates only ✅ Limit funding - Only keep necessary AKT (monthly costs + buffer) ✅ Secure mnemonic - Use environment variables or secrets manager ✅ Never commit .env - Already in .gitignore ✅ Monitor activity - Set up alerts for unusual transactions

Best Practices

# DON'T: Store mnemonic in code
const mnemonic = "word1 word2 word3..."

# DO: Load from environment (not secure for production)
const mnemonic = process.env.MNEMONIC

# BETTER: Use secrets manager (production)
const mnemonic = await secretsManager.getSecret("hermes-mnemonic")

🔧 Troubleshooting

Common Issues

"Client not initialized"

# Solution: Ensure initialize() is called
await client.initialize()

"Insufficient funds"

# Check wallet balance
akash query bank balances <YOUR_ADDRESS>

# Fund wallet
akash tx bank send <FROM> <ORACLE_ADDRESS> 100000000uakt --gas auto

"Failed to fetch from Hermes"

# Test Hermes API
curl "https://hermes.pyth.network/v2/updates/price/latest?ids=<PRICE_FEED_ID>"

# Check price feed ID
akash query wasm contract-state smart $CONTRACT_ADDRESS '{"get_price_feed_id":{}}'

"Price already up to date"

  • Not an error! Contract already has the latest price
  • Client will try again on next interval

Debug Mode

# Enable verbose logging
export DEBUG=*
npm run cli:daemon

Test Connectivity

# Test RPC
curl $RPC_ENDPOINT/status

# Test Hermes
curl "https://hermes.pyth.network/api/latest_price_feeds?ids[]=<FEED_ID>"

# Test contract
akash query wasm contract-state smart $CONTRACT_ADDRESS '{"get_config":{}}'

📚 Documentation

For more detailed information:

🆘 Support

📄 License

MIT License


Ready to deploy! 🚀

Start with: npm install && cp .env.example .env

About

No description, website, or topics provided.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

 
 
 

Contributors 2

  •  
  •