Quick reference for all JavaScript/Node.js scripts in the repository.
Location: scripts/bot/operators-bot.mjs
Purpose: Automated price submission bot for testing and local development.
# Replace with your deployed oracle address
node scripts/bot/operators-bot.mjs \
--rpc http://127.0.0.1:8545 \
--oracle 0x5FbDB2315678afecb367f032d93F642f64180aa3 \
--feedDesc "ar/bytes-testv1" \
--interval 30000node scripts/bot/operators-bot.mjs \
--rpc http://127.0.0.1:8545 \
--oracle 0x5FbDB2315678afecb367f032d93F642f64180aa3 \
--feedDesc "ar/bytes-testv1" \
--interval 30000| Variable | Description | Default |
|---|---|---|
RPC_URL |
RPC endpoint | http://127.0.0.1:8545 |
ORACLE |
Oracle contract address | Required |
FEED_DESC |
Feed identifier string | ar/bytes-testv1 |
FEED_ID |
Alternative: feedId bytes32 | Computed from FEED_DESC |
INTERVAL_MS |
Submission interval (ms) | 30000 |
NUM_OPS |
Number of operators | 6 |
PRIVATE_KEYS_JSON |
Custom operator keys array | Anvil test keys |
--rpc <url> # RPC endpoint
--oracle <address> # Oracle contract address
--feedDesc <string> # Feed identifier
--feedId <bytes32> # Alternative to feedDesc
--interval <ms> # Submission interval
--ops <number> # Number of operators- Dynamic operator initialization: Matches on-chain operators with available keys
- Sequential submissions: Avoids race conditions by submitting one at a time
- Automatic recovery: Calls
poke()after 2 consecutive failed ticks - Pause detection: Automatically pauses when oracle is paused
- Comprehensive error handling: Gracefully handles all oracle error types
- Real-time logging: Shows submission status, round progression, price age
🚀 Operator bot starting
rpc=http://127.0.0.1:8545 oracle=0x5FbD…0aa3 feed=ar/bytes-testv1 ops=6 interval=30000ms
✅ Initialized 6/6 valid operator wallets
📤 Starting new round 25 for ar/bytes-testv1
✍️ 0xf39F…2266 → 9923000000 ✅ 0x4538…b681
✍️ 0x7099…79C8 → 9958000010 ✅ 0x4d80…fbc0
✍️ 0x3C44…93BC → 9981000020 ✅ 0xcb85…4de9
✅ Quorum (3) reached—skipping remaining operators
📊 3/6 operators submitted successfully
🟢 latest round=25 answer=9981000020 age=1s changed=🔄
The bot recognizes and handles these oracle errors:
| Error Code | Name | Meaning | Bot Action |
|---|---|---|---|
0x32e1428f |
RoundFull | Round has maxSubmissions | Skip gracefully |
0x8daa9e49 |
DuplicateSubmission | Already submitted this round | Skip gracefully |
0xc3fa7054 |
WrongRound | Round changed mid-submission | Skip gracefully |
0x47a2375f |
NotDue | Heartbeat not met yet | Skip gracefully |
0xd93c0665 |
EnforcedPause | Oracle is paused | Skip gracefully |
0x7c214f04 |
NotOperator | Not authorized operator | Error (critical) |
For production use:
- Convert to TypeScript for type safety
- Add structured logging (Winston, Pino)
- Export metrics (Prometheus format)
- Add health check endpoint
- Use KMS for key management (never raw private keys)
- Deploy with redundancy (multiple bots, different regions)
See operator-guide.md for production setup details.
Location: scripts/test-adapter-consumer.mjs
Purpose: End-to-end integration testing of oracle → adapter → consumer flow.
# Replace with your deployed addresses, then run
export ORACLE=0x5FbDB2315678afecb367f032d93F642f64180aa3
export ADAPTER=0xD9164F568A7d21189F61bd53502BdE277883A0A2
export CONSUMER=0x610178dA211FEF7D417bC0e6FeD39F05609AD788
node scripts/test-adapter-consumer.mjs# Set deployed addresses
export ORACLE=0x5FbDB2315678afecb367f032d93F642f64180aa3
export ADAPTER=0xD9164F568A7d21189F61bd53502BdE277883A0A2
export CONSUMER=0x610178dA211FEF7D417bC0e6FeD39F05609AD788
# Run test
node scripts/test-adapter-consumer.mjs| Variable | Description | Default |
|---|---|---|
RPC_URL |
RPC endpoint | http://127.0.0.1:8545 |
ORACLE |
Oracle contract address | 0x5FbDB2315678afecb367f032d93F642f64180aa3 |
ADAPTER |
Adapter contract address | 0xD9164F568A7d21189F61bd53502BdE277883A0A2 |
CONSUMER |
Consumer contract address | 0x610178dA211FEF7D417bC0e6FeD39F05609AD788 |
-
Oracle Functionality
- Fetches
latestRoundData(feedId) - Reads
getConfig(feedId)for decimals/description - Verifies data is present and valid
- Fetches
-
Adapter Compatibility
- Tests Chainlink
AggregatorV3Interface - Verifies data matches oracle exactly
- Tests
decimals(),description(),version() - Tests
latestRoundData()andgetRoundData(roundId)
- Tests Chainlink
-
Consumer Integration
- Verifies consumer reads from correct adapter
- Tests consumer's
latest()function - Confirms data consistency across all layers
-
Historical Data
- Fetches previous rounds via oracle and adapter
- Verifies historical continuity
🧪 Testing Adapter & Consumer Integration
Configuration:
Oracle: 0x5FbD…0aa3
Adapter: 0xD916…A0A2
Consumer: 0x6101…D788
Feed: ar/bytes-testv1
📊 Testing Oracle...
✅ Latest Round Data:
Round ID: 11
Answer: 9992000030 (99.9200003)
Decimals: 8
Description: AR/byte test feed
Age: 20s
🔌 Testing Adapter (Chainlink-compatible)...
✅ Latest Round Data:
Round ID: 11
Answer: 9992000030
✅ Adapter data matches Oracle
🛒 Testing Consumer Contract...
✅ Latest Data:
Answer: 9992000030
✅ Consumer data matches Oracle & Adapter
📜 Testing Historical Data Access...
✅ Historical data available
═══════════════════════════════════════
✅ ALL TESTS PASSED!
═══════════════════════════════════════
"No data present" error:
- Ensure operator bot has submitted at least one round
- Check that feed exists in oracle (
getConfigshould not revert)
"Adapter data mismatch" error:
- Verify adapter is pointing to correct oracle
- Check that feedId matches
"Consumer not found" error:
- Deploy TestPriceConsumer first using Foundry script
# 1. Start local Anvil node (separate terminal)
anvil
# 2. Deploy oracle, factory, and feeds (separate terminal)
export ADMIN=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
export ADMIN_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
make anvil-bootstrap-all
# 3. Note deployed addresses from output
export ORACLE=0x5FbDB...
export FACTORY=0xe7f17...
export ADAPTER=0xD916...
# 4. Deploy test consumer
forge script script/DeployTestConsumer.s.sol:DeployTestConsumer \
--rpc-url http://127.0.0.1:8545 \
--broadcast \
--sender $ADMIN \
--private-key $ADMIN_PRIVATE_KEY
export CONSUMER=0x6101...
# 5. Start operator bot (separate terminal)
node scripts/bot/operators-bot.mjs \
--rpc http://127.0.0.1:8545 \
--oracle $ORACLE \
--feedDesc "ar/bytes-testv1" \
--interval 30000
# 6. Wait for 1-2 rounds to complete (~1 minute)
# 7. Run integration tests
node scripts/test-adapter-consumer.mjsBoth scripts require:
{
"type": "module",
"dependencies": {
"ethers": "^6.13.2"
}
}Install with:
npm install- Operator Guide - Production operator setup
- Deployment Cookbook - Deployment commands and examples
- Adapter Guide - Adapter architecture and usage
- Maintenance Guide - Operational procedures
- Operator Bot Fix Report - Detailed bot architecture and troubleshooting
When adding new scripts:
- Use ES modules (
type: "module"in package.json) - Use ethers v6 syntax
- Support both CLI args and environment variables
- Add clear usage examples to this document
- Include error handling for all expected failures
- Log actions clearly with appropriate emoji/formatting