Automated service that fetches FLOW token prices from CoinGecko and updates both the Flow blockchain PriceOracle contract and the backend PostgreSQL database.
- ✅ Fetches real-time FLOW/USD price from CoinGecko API
- ✅ Updates price on Flow blockchain (testnet) every 5 minutes
- ✅ Stores historical price data in PostgreSQL database
- ✅ Calculates and stores protocol APY snapshots based on FLOW price
- ✅ Supports multiple staking protocols (Ankr, Increment, Figment)
- ✅ Automatic retry and error handling
- ✅ Comprehensive logging
- ✅ Auto-loads .env configuration
┌─────────────────┐
│ CoinGecko API │ ← Fetch FLOW price
└────────┬────────┘
│
▼
┌─────────────────────────────┐
│ Price Oracle Updater │
│ • Update blockchain price │
│ • Store price history │
│ • Calculate protocol APYs │
└────┬───────┬────────────┬───┘
│ │ │
│ │ └────────────┐
│ └──────────────┐ │
▼ ▼ ▼
┌──────────┐ ┌─────────────────┐ ┌────────────────┐
│ Flow │ │ price_oracle │ │ protocol_apy_ │
│Blockchain│ │ table │ │ snapshots │
│(Testnet) │ │ (PostgreSQL) │ │ (PostgreSQL) │
└──────────┘ └─────────────────┘ └────────────────┘
- Go 1.21 or later
- PostgreSQL database (shared with backend)
- Flow blockchain account with PriceOracle admin access
-
Clone and navigate to the directory
cd cron-oracle -
Install dependencies
go mod tidy
-
Run the database migration
psql $DATABASE_URL -f ../backend/migrations/007_price_oracle.sql -
Configure environment variables
cp .env.example .env # Edit .env with your configuration
Create a .env file with the following variables:
# Database Configuration
DATABASE_URL=postgresql://user:password@localhost:5432/trixy-flow-indexer
# Flow Blockchain Configuration
FLOW_PRIVATE_KEY=your_private_key_here
FLOW_ACCOUNT_ADDRESS=0x0a80bc2ee7f90ab5
PRICE_ORACLE_CONTRACT=0x0a80bc2ee7f90ab5| Variable | Description | Required |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | ✅ Yes |
FLOW_PRIVATE_KEY |
Private key (ECDSA_secp256k1) with admin access | ✅ Yes |
FLOW_ACCOUNT_ADDRESS |
Flow account address with admin rights | ✅ Yes |
PRICE_ORACLE_CONTRACT |
PriceOracle contract address | ✅ Yes |
./run.shThis automatically loads .env and starts the service.
export $(cat .env | grep -v '^#' | xargs)
go run main.gogo build -o oracle main.go
./oracle- Price Fetching: Every 5 minutes, fetches current FLOW/USD price from CoinGecko
- Blockchain Update: Sends transaction to update PriceOracle contract on Flow testnet
- Database Storage: Saves price data with transaction hash to
price_oracletable - APY Calculation: Calculates protocol APY based on FLOW price (lower price = higher APY)
- APY Storage: Saves APY snapshots for Ankr, Increment, and Figment to
protocol_apy_snapshotstable - Logging: Logs all operations (success/failure) to stdout
┌─────────────────────────────────────────┐
│ Fetch Price from CoinGecko │
│ (e.g., $0.2784) │
└────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Update Flow Blockchain │
│ - Create & sign transaction │
│ - Send to PriceOracle contract │
│ - Wait for seal │
└────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Save Price to Database │
│ - Insert to price_oracle table │
│ - Store TX hash & timestamp │
└────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Calculate Protocol APYs │
│ - Ankr: 12.5% base × price impact │
│ - Increment: 15.3% base × impact │
│ - Figment: 10.8% base × impact │
└────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Save APY Snapshots │
│ - Insert to protocol_apy_snapshots │
│ - Link to price_oracle record │
└─────────────────────────────────────────┘
│
▼
Wait 5 minutes ⏱️
│
└──────────────┐
│
▼
Repeat cycle...
The service uses two tables:
CREATE TABLE price_oracle (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
symbol VARCHAR(20) NOT NULL,
price_usd DECIMAL(20, 8) NOT NULL,
tx_hash TEXT,
block_number BIGINT,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);CREATE TABLE protocol_apy_snapshots (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
protocol_name VARCHAR(50) NOT NULL,
apy DECIMAL(10, 4) NOT NULL,
flow_price DECIMAL(20, 8) NOT NULL,
price_oracle_id UUID REFERENCES price_oracle(id),
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);Get latest price:
SELECT * FROM price_oracle
WHERE symbol = 'FLOW'
ORDER BY created_at DESC
LIMIT 1;Get price history (24 hours):
SELECT * FROM price_oracle
WHERE symbol = 'FLOW'
AND created_at > NOW() - INTERVAL '24 hours'
ORDER BY created_at DESC;Calculate average price:
SELECT
DATE_TRUNC('hour', created_at) as hour,
AVG(price_usd) as avg_price,
MIN(price_usd) as min_price,
MAX(price_usd) as max_price
FROM price_oracle
WHERE symbol = 'FLOW'
GROUP BY hour
ORDER BY hour DESC;Get latest APY for all protocols:
SELECT DISTINCT ON (protocol_name)
protocol_name,
apy,
flow_price,
created_at
FROM protocol_apy_snapshots
ORDER BY protocol_name, created_at DESC;Get APY history with price:
SELECT
a.protocol_name,
a.apy,
a.flow_price,
p.tx_hash,
a.created_at
FROM protocol_apy_snapshots a
JOIN price_oracle p ON a.price_oracle_id = p.id
WHERE a.protocol_name = 'ankr'
ORDER BY a.created_at DESC
LIMIT 10;./test_db.shThis verifies:
- ✅ Database table exists
- ✅ Can insert records
- ✅ Can query records
- ✅ Indexes are working
curl -s "https://api.coingecko.com/api/v3/simple/price?ids=flow&vs_currencies=usd" | python3 -m json.toolThe service outputs structured logs:
🚀 Starting FLOW price oracle updater
📊 Update interval: 5m0s
📍 Contract address: 0x0a80bc2ee7f90ab5
🌐 Network: Flow Testnet
✅ Flow account loaded: 0a80bc2ee7f90ab5 (keys: 1)
✅ Database connection established
💰 Fetched FLOW price: $0.2784
✅ Price updated to $0.2784 (TX: 11b0313b...)
💾 Price saved to database (ID: 0876c2bb...)
📈 ankr APY: 21.52% (price impact: 1.72x)
📈 increment APY: 26.34% (price impact: 1.72x)
📈 figment APY: 18.59% (price impact: 1.72x)
- 🚀 Service started
- 💰 Price fetched
- ✅ Operation successful
- ❌ Error occurred
- 💾 Database operation
- 📊 Status information
-
Use systemd service (Linux)
[Unit] Description=Trixy Price Oracle After=network.target postgresql.service [Service] Type=simple User=trixy WorkingDirectory=/opt/trixy/cron-oracle EnvironmentFile=/opt/trixy/cron-oracle/.env ExecStart=/opt/trixy/cron-oracle/oracle Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
-
Monitor logs
journalctl -u trixy-oracle -f
-
Set up alerts for:
- Price fetch failures
- Blockchain transaction failures
- Database connection issues
1. "failed to connect to Flow"
- Check internet connection
- Verify Flow testnet is accessible:
access.devnet.nodes.onflow.org:9000
2. "failed to decode private key"
- Ensure
FLOW_PRIVATE_KEYis valid hex string - Check key format (should be 64 hex characters)
3. "failed to connect to database"
- Verify PostgreSQL is running
- Check
DATABASE_URLformat - Ensure database exists and migrations are run
4. "transaction failed: Could not borrow admin resource"
- Account doesn't have admin access to PriceOracle contract
- Verify correct account address and private key
5. "Error fetching price"
- CoinGecko API might be rate-limited
- Check internet connection
- Verify API endpoint is accessible
cron-oracle/
├── main.go # Main application code
├── go.mod # Go dependencies
├── go.sum # Dependency checksums
├── .env # Environment configuration (gitignored)
├── .env.example # Environment template
├── .gitignore # Git ignore rules
├── run.sh # Startup script
├── test_db.sh # Database test script
├── README.md # This file
├── README_DB.md # Database integration docs
└── SETUP_COMPLETE.md # Setup summary
Endpoint:
GET https://api.coingecko.com/api/v3/simple/price?ids=flow&vs_currencies=usd
Response:
{
"flow": {
"usd": 0.276873
}
}Contract Address: 0xe3f7e4d39675d8d3 (Testnet)
Transaction Script:
import PriceOracle from 0xe3f7e4d39675d8d3
transaction(newPrice: UFix64) {
prepare(signer: auth(Storage) &Account) {
let admin = signer.storage.borrow<&PriceOracle.Admin>(
from: PriceOracle.AdminStoragePath
) ?? panic("Could not borrow admin resource")
admin.updateFlowPrice(newPrice: newPrice)
}
}When contributing, ensure:
- Code compiles:
go build - Tests pass:
./test_db.sh - Environment variables are documented
- Logs are clear and helpful
Part of the Trixy Protocol project.
For issues or questions:
- Check the troubleshooting section
- Review logs for error messages
- Verify all environment variables are set correctly
- Test database connection with
./test_db.sh
Note: This service is designed for Flow testnet. For mainnet deployment, update the flowAccessNode constant and contract address in main.go.