# Allora Network Documentation > Allora is a self-improving decentralized AI network: an open-source marketplace for machine intelligence where workers supply ML inferences, reputers score them against ground truth, and validators secure the chain. > These docs cover getting started, building workers and reputers, consuming inference, operating the network, the concepts behind it, and reference material. This file is the complete text of every page on https://docs.allora.network/, in site navigation order. Each page starts with a thematic break, its title as an H1, and the canonical URL it was generated from. The page index alone is at https://docs.allora.network/llms.txt. --- # Get Started Source: https://docs.allora.network/get-started Pick your path into Allora — deploy a model, enter Forge, consume inference, or point your AI agent at the docs. Allora is a decentralized network where machine-learning models compete to produce the best inferences. Pick the job you want to do — each card shows roughly how long it takes. - [Deploy a model · 10 min](https://docs.allora.network/get-started/quickstart-worker) - [Enter Forge · 15 min](https://docs.allora.network/get-started/quickstart-forge) - [Consume inference · 2 min](https://docs.allora.network/get-started/quickstart-consume) - [Point your agent here · 1 min](https://docs.allora.network/get-started/quickstart-agents) - **Deploy a model** — run a Python inference worker that submits live predictions to the testnet sandbox topic. No wallet setup, no funding steps, no penalties for inaccurate inferences. Start with [Deploy a worker in 10 minutes](https://docs.allora.network/get-started/quickstart-worker). - **Enter Forge** — compete in the [Allora Model Forge Competition](https://docs.allora.network/build/forge/competitions): build the best model for a live topic and earn rewards based on accuracy. Start with [Enter a Forge competition](https://docs.allora.network/get-started/quickstart-forge). - **Consume inference** — query the network's aggregated predictions over REST or the TypeScript/Python/Go SDKs. Start with [Consume an inference in 2 minutes](https://docs.allora.network/get-started/quickstart-consume), then explore the [consumer docs](https://docs.allora.network/consume/overview). - **Point your agent here** — hand your AI assistant the [agent quickstart](https://docs.allora.network/get-started/quickstart-agents), a page written to be read by the agent itself: guardrails, the machine-readable docs index ([/llms.txt](https://docs.allora.network/llms.txt)), and a runnable path to a live testnet submission. ## Set up the basics These pages cover the underlying tooling that every path eventually touches: - [Setup Wallet](https://docs.allora.network/get-started/setup-wallet) — create a wallet, request testnet funds from the faucet, and find explorer/RPC URLs. - [Installation](https://docs.allora.network/get-started/cli) — install the `allorad` CLI to query the chain and send transactions directly. - [Basic Usage](https://docs.allora.network/get-started/basic-usage) — first queries and staking operations with `allorad`. - [Networks](https://docs.allora.network/reference/networks) — chain IDs, endpoints, and deployed versions for testnet and mainnet. --- # Deploy a worker in 10 minutes Source: https://docs.allora.network/get-started/quickstart-worker Run a Python inference worker that submits a live prediction to Allora's testnet sandbox topic. ## Goal Run an inference worker on your machine that submits a prediction to the Allora testnet and see it confirmed on-chain. The worker targets **topic 69**, the testnet sandbox ("PLAYGROUND: 1 day BTC/USD Price Prediction") — a topic for newcomers where inaccurate inferences carry no penalty. Everything is automatic: the SDK generates a wallet for you, uses your API key to request testnet ALLO from the faucet for gas, registers your worker on the topic, and submits your model's prediction each epoch. ## Prerequisites - Python 3.10 or newer - A free Allora API key from [developer.allora.network](https://developer.allora.network) — the worker uses it to faucet testnet gas; no wallet setup and no funding steps ## Steps ### 1. Install the SDK Create a project directory with a fresh virtual environment and install [`allora_sdk`](https://github.com/allora-network/allora-sdk-py): ```bash mkdir allora-quickstart && cd allora-quickstart python3 -m venv .venv && source .venv/bin/activate pip install allora_sdk ``` ### 2. Create the worker Save this as `quickstart_worker.py`. The `run_model` function is called once per epoch; whatever float it returns is submitted as your inference. The placeholder value stands in for your model's prediction logic. ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext async def run_model(ctx: RunContext) -> float: # Replace this with your model's prediction logic. return 123.45 async def main(): worker = AlloraWorker.inferer( topic_id=69, # sandbox topic: no penalty for inaccurate inferences network=AlloraNetworkConfig.testnet(), api_key=os.environ["ALLORA_API_KEY"], # used to faucet testnet gas run=run_model, ) async for result in worker.run(): if isinstance(result, Exception): print(f"Inference worker error: {result}") else: print(f"Prediction submitted to Allora: {result.submission}") asyncio.run(main()) ``` ### 3. Run it ```bash export ALLORA_API_KEY="" python quickstart_worker.py ``` On first run you are asked for a wallet mnemonic — press **Enter** to have one generated. It is saved to `.allora_key` (permissions `0600`) in the current directory and reused automatically on later runs. You should see output like this (address and hashes will differ): ```text No mnemonic or private key provided. Enter your Allora wallet mnemonic or press to have one generated for you. Mnemonic: Mnemonic saved to .allora_key (file permissions: 0600) _ _ _ ___ ____ _ / \ | | | | / _ \| _ \ / \ / _ \ | | | | | | | | |_) | / _ \ / ___ \| |___| |__| |_| | _ < / ___ \ Chain: allora-testnet-1 /_/ \_\_____|_____\___/|_| \_\/_/ \_\ Topic: PLAYGROUND: 1 day BTC/USD Price Prediction (ID: 69) __ _____ ____ _ _______ ____ Address: allo1p0pd89cw50l0s20fjggjqkcpx0svx822t9xuqj \ \ / / _ \| _ \| |/ / ____| _ \ Role: INFERER \ \ /\ / / | | | |_) | ' /| _| | |_) | \ V V /| |_| | _ <| . \| |___| _ < \_/\_/ \___/|_| \_\_|\_\_____|_| \_\ 2026-07-30 16:55:14,241 INF Worker wallet: allo1p0pd89cw50l0s20fjggjqkcpx0svx822t9xuqj || Balance: 0.000000000000000000 ALLO 2026-07-30 16:55:14,279 INF Requesting ALLO from testnet faucet... 2026-07-30 16:55:14,821 INF Request sent... 2026-07-30 16:55:19,861 INF Balance: 0.000000001000000000 ALLO 2026-07-30 16:55:38,767 INF ✅ Registered inferer allo1p0pd89cw50l0s20fjggjqkcpx0svx822t9xuqj for topic 69 2026-07-30 16:55:38,770 INF 🔄 Starting polling worker 2026-07-30 16:55:38,993 INF Topic 69: unfulfilled nonces: {10297079} 2026-07-30 16:55:39,028 INF 👉 Found new nonce 10297079 for topic 69, submitting... account_seq=2 2026-07-30 16:55:39,069 WRN ⚠️⚠️⚠️ SANITY CHECK WARNING: Your prediction (123.450000) is 329.3 standard deviations from the network consensus (mean: 64603.618208, std: 195.817539). Please verify you're predicting the correct target variable and using the right units. 2026-07-30 16:55:49,860 INF ✅ Successfully submitted: topic=69 nonce=10297079 2026-07-30 16:55:49,860 INF - Transaction hash: 5456F7849BE2B58B7215146B6CADD5D5CBD17259792200ABD3DC79ED69B92DB3 2026-07-30 16:55:49,860 INF - View on explorer: https://testnet.explorer.allora.network/explorer/transactions/5456F7849BE2B58B7215146B6CADD5D5CBD17259792200ABD3DC79ED69B92DB3 Prediction submitted to Allora: 123.45 ``` The **sanity check warning** is expected here: topic 69 asks for a 1-day BTC/USD price prediction, and the snippet's placeholder value `123.45` is far from the network consensus. Replace `run_model`'s body with a real prediction to clear it. The worker keeps running and submits again whenever a new submission window opens. Stop it with `Ctrl+C`. ## Verify 1. **In the console** — look for `✅ Successfully submitted` followed by a transaction hash, and your script's own `Prediction submitted to Allora: 123.45` line. 2. **On-chain** — query the transaction hash from your output against the testnet API: ```bash curl -s "https://allora-api.testnet.allora.network/cosmos/tx/v1beta1/txs/" ``` A successful submission returns `"code": 0` in `tx_response`, and the message type `/emissions.v10.InsertWorkerPayloadRequest` with `"topic_id": "69"`. 3. **On the explorer** — open the [testnet explorer](https://explorer.testnet.allora.network/allora-testnet-1) and paste your worker address (printed in the startup banner) into the search bar to see your wallet, its faucet funding, and your submissions. ## Troubleshoot - **`unknown service emissions.v9.QueryService`** — your installed `allora_sdk` release predates the testnet's `emissions/v10` upgrade (see [Networks](https://docs.allora.network/reference/networks)). Upgrade with `pip install --upgrade allora_sdk`. - **Faucet rate-limited** (`Too many faucet requests`) — wait a few minutes and rerun, or request funds manually at [https://faucet.testnet.allora.network](https://faucet.testnet.allora.network) for the address shown in your startup banner, then rerun the worker. - **Worker sits idle** (`Our unfulfilled nonces: -`) — the topic's current submission window has already been fulfilled or closed. Leave the worker running; it submits automatically when the next window opens. - **Wrong or lost identity** — the wallet mnemonic lives in `.allora_key` in the directory you ran the worker from, and is auto-detected on rerun. Run from the same directory to reuse it, or delete the file to generate a fresh identity. - **`not whitelisted on topic`** — topic 69 is open to everyone, but other topics may restrict who can submit. Contact the topic creator to be whitelisted. ## Next - **Build a real model** — the [Allora Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit) walks you from historical Allora datasets through feature engineering and evaluation to a deployed worker, with a monitoring dashboard built in. To compete with it, [enter the Forge competition](https://docs.allora.network/build/forge/competitions). - **Monitor your worker** — track your submissions and scores on-chain with [worker data queries](https://docs.allora.network/build/worker/query-worker-data) and your [EMA score](https://docs.allora.network/build/worker/monitoring#5-query-ema-scores-with-allorad). - **Go to mainnet** — switch the snippet to `network=AlloraNetworkConfig.mainnet()` and fund your wallet with real ALLO (mainnet has no faucet). Endpoints and chain IDs are listed in [Networks](https://docs.allora.network/reference/networks). --- # Enter a Forge competition Source: https://docs.allora.network/get-started/quickstart-forge Train, grade, and deploy a baseline model with the Allora Forge Builder Kit, then enter a live competition on forge.allora.network. ## Goal Go from a fresh clone to a competing model with the [Allora Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit): backfill historical BTC data, train a baseline model, grade it against Allora's evaluation metrics, deploy it as a live worker on the testnet sandbox topic (**69**, 1-day BTC/USD price prediction — no whitelist, no penalties), and then enter a competition on [forge.allora.network](https://forge.allora.network). Budget about 15 minutes; the training script itself runs in roughly 3 minutes. ## Prerequisites - Python 3.10 or newer (on macOS, use `python3.11` or `python3.12` explicitly if your system `python3` is 3.9) - `git` - A free Allora API key — created in the next step (or skip it and use the Binance data fallback) ## Steps ### 1. Create an API key Sign up free at [developer.allora.network](https://developer.allora.network) and copy your API key. The key unlocks the kit's default **Atlas** data source (Tiingo 1-minute candles) and is also used by the deployed worker. No API key? The data pipeline can pull from Binance instead — see the fallback note in step 3. ### 2. Clone and install ```bash git clone https://github.com/allora-network/allora-forge-builder-kit.git cd allora-forge-builder-kit python3.11 -m venv .venv source .venv/bin/activate python -m pip install . python -m pip install -r requirements.txt ``` Save your API key into the repo directory and load it into the environment without displaying it: ```bash echo "UP-..." > .allora_api_key # Load into env without displaying the value export ALLORA_API_KEY=$(cat .allora_api_key) ``` (Replace `UP-...` with the key you copied in step 1.) ### 3. Backfill data and train a baseline ```bash cd notebooks python example_topic_69_bitcoin_walkthrough.py ``` The walkthrough script runs the whole modeling pipeline for topic 69 (~3 minutes): 1. **Backfill** — constructs an `AlloraMLWorkflow` on the Atlas data source and calls `backfill()` to download 500 days of 1-minute BTC/USD candles. 2. **Features and target** — `get_full_feature_target_dataframe()` resamples to 1-hour bars and builds, for each timestamp, 48 input bars × 5 normalized OHLCV ratios = 240 base features (plus four engineered log-return features), with the 24-hour-ahead log return as the target. 3. **Train** — grid-searches a LightGBM baseline with walk-forward cross-validation (an embargo gap prevents lookahead leakage), then retrains the best configuration on the full dataset. 4. **Evaluate** — grades the held-out predictions with `PerformanceEvaluator` (next step). 5. **Save** — tests one live prediction and saves the model as `predict.pkl`, the artifact the worker will serve. Topic 69 is a *price* topic, so the saved function converts the predicted log return into an absolute USD price. **No API key?** Edit the `AlloraMLWorkflow(...)` call in the walkthrough script to use `data_source="binance"` (and drop the `api_key` argument) to pull data from Binance instead. The fallback covers training data only — deploying in step 5 still requires `ALLORA_API_KEY`. ### 4. Read your evaluation report `PerformanceEvaluator` scores the model's out-of-sample predictions on 7 primary metrics, each with a pass/fail threshold: 1. **Directional Accuracy** (≥ 0.52) — fraction of predictions whose sign (up/down) matches the actual return. 2. **DA CI Lower Bound** (≥ 0.50) — lower bound of the 95% Wilson confidence interval for directional accuracy, using an autocorrelation-adjusted effective sample size. 3. **DA Statistical Significance** (p < 0.05) — z-test with continuity correction against the null hypothesis that directional accuracy is 50%. 4. **Pearson Correlation** (r ≥ 0.05) — linear correlation between predicted and actual returns. 5. **Pearson Statistical Significance** (p < 0.05) — significance of that correlation. 6. **WRMSE Improvement** (≥ 5%) — weighted RMSE versus a zero-prediction baseline, with errors weighted by the magnitude of the actual return. 7. **CZAR Improvement** (≥ 10%) — Cumulative Z-scored Absolute Return: the fraction of z-scored directional return captured versus a perfect oracle (0 = random guessing, 1 = every directional call correct). The number of metrics passed (out of 7) maps to a letter grade: | Points (out of 7) | 7 | 6 | 5 | 4 | 3 | 2 | ≤ 1 | |-------------------|---|---|---|---|---|---|-----| | Grade | A+ | A | B+ | B | C | D | F | The report is printed near the end of the walkthrough. Here is a real run (your numbers will differ as new market data arrives): ```text ================================================================================ PERFORMANCE EVALUATION REPORT ================================================================================ OVERALL PERFORMANCE: F (1/7 points) Primary metrics passed: 1/7 Performance Score: 14.29% ================================================================================ PRIMARY METRICS (7 Core Metrics) ================================================================================ 1. Directional Accuracy: Value: 0.4842 FAIL Threshold: >= 0.52 Correct: 4329/8940 predictions 2. DA CI Lower Bound: Value: 0.4670 FAIL Threshold: >= 0.5 95% CI: [0.4670, 0.5015] Effective n: 3218.6 (autocorr: 0.471) 3. DA Statistical Significance: p-value: 0.5000 FAIL Threshold: < 0.05 Method: z-test with continuity correction (n_eff=3218.6) 4. Pearson Correlation: r: -0.0209 FAIL Threshold: >= 0.05 5. Pearson Statistical Significance: p-value: 0.0477 PASS Threshold: < 0.05 6. WRMSE Improvement: Improvement: -0.0264 (-2.64%) FAIL Threshold: >= 0.05 (5%) Model WRMSE: 0.038048 Baseline WRMSE: 0.037069 7. CZAR Improvement: Improvement: -0.0675 (-6.75%) FAIL Threshold: >= 0.1 (10%) Model CZAR: -441.157988 Oracle CZAR: 6531.829579 ================================================================================ ``` A higher grade means better generalization — and a higher expected score once the model competes on the network. Don't be discouraged by a low grade here: crypto returns are noise-dominated and the stock baseline is only a starting point. Beating it with your own features is the whole game (see [Next](#next)). ### 5. Deploy the worker ```bash # Still in notebooks/ python deploy_worker.py ``` On first run, `WorkerManager` creates a wallet (key file in `worker_keys/`), requests testnet ALLO from the faucet automatically, registers the worker, and starts the worker process, which polls the chain for open submission windows and serves `predict.pkl`: ```text Deploying worker for Topic 69... Deployed worker for topic 69 with address allo14lv0hjr4hzvsdyv7awxjaf9f8ajxeqwcmxrpyg Address: allo14lv0hjr4hzvsdyv7awxjaf9f8ajxeqwcmxrpyg Starting worker... Status: running PID: 99461 Log: worker_logs/worker_69_allo14lv0hjr4hzvsdyv7awxjaf9f8ajxeqwcmxrpyg.log Worker running. Monitor with: python -m allora_forge_builder_kit.workerctl dashboard python -m allora_forge_builder_kit.web_dashboard ``` Faucet activity is logged, not printed: wallet funding, balance checks, and on-chain errors all go to `worker_logs/worker_69_
.log`. ### 6. Watch it submit ```bash # Web dashboard (recommended) — open http://localhost:8787 python -m allora_forge_builder_kit.web_dashboard ``` The dashboard auto-refreshes every 5 seconds and shows every worker with its submission timeline, on-chain scores, and live log tail. Prefer the terminal? ```bash # CLI dashboard — text summary of all workers python -m allora_forge_builder_kit.workerctl dashboard ``` ### 7. Enter the competition Your worker is already scoring on-chain in the topic-69 sandbox. To compete for rewards: 1. **Create a Forge account** at [forge.allora.network](https://forge.allora.network) and connect a wallet. 2. **Register** for a competition — participation requires registering and getting whitelisted; the Forge site links to the registration form. 3. **Link your worker** to your Forge account with `python -m allora_forge_builder_kit.workerctl link` — the kit's device flow signs with your on-disk worker key, so your mnemonic never leaves your machine. 4. **Track your standing** on the per-topic leaderboards. How competitions, scoring, and mainnet graduation work is covered in [Forge competitions](https://docs.allora.network/build/forge/competitions). ## Verify 1. **Model artifact** — the walkthrough ends with `COMPLETE!` and a `predict.pkl` file in `notebooks/`, plus run artifacts (metrics, predictions CSV, scatter plot) under `notebooks/runs//`. 2. **Worker submits** — check the worker log for a successful on-chain submission: ```bash grep "Successfully submitted" worker_logs/worker_69_*.log ``` You should see a line like `✅ Successfully submitted: topic=69 nonce=...` followed by a transaction hash. 3. **Dashboard** — http://localhost:8787 lists your worker as `running` with a recent submission in its timeline. 4. **Explorer** — paste the worker address (printed by `deploy_worker.py`) into the [testnet explorer](https://explorer.testnet.allora.network/allora-testnet-1) to see its faucet funding and submissions on-chain. ## Troubleshoot - **`OSError: Library not loaded: @rpath/libomp.dylib`** (macOS) — LightGBM needs the OpenMP runtime: `brew install libomp`, then rerun the walkthrough. - **`RuntimeError: No data available`** — the backfill failed, usually a missing or invalid API key. Confirm the key is loaded without printing it (`[ -n "$ALLORA_API_KEY" ] && echo "key loaded"`), recheck `.allora_api_key`, or switch the walkthrough to `data_source="binance"`. - **Worker fails to start or never submits** — the worker runs as a subprocess, so look in `worker_logs/worker_69_
.log`: faucet requests, balance checks, and on-chain errors all appear there, not on your console. - **`unknown service emissions.v9.QueryService`** in the worker log — the installed `allora_sdk` release predates the testnet's `emissions/v10` upgrade (see [Networks](https://docs.allora.network/reference/networks)). Upgrade it inside the kit's venv: `pip install --upgrade allora_sdk`. - **`not whitelisted on topic`** — playground topics 69 and 77 are open to everyone; other topics require competition registration (step 7) before the chain accepts your submissions. ## Next - **Beat the baseline** — add technical indicators, log-return series, or cross-asset signals: `notebooks/feature_engineering_example.py` is the reference, and the kit's `allora_research_model_skills/` bundle packages three model-building methodologies for AI-assisted research. - **Deploy more topics** — `TOPIC_ID=77 python deploy_worker.py` deploys the same artifact to another topic; browse [existing topics](https://docs.allora.network/build/forge/topics) and discover them programmatically with `AlloraTopicDiscovery`. - **Understand the competition** — [how Forge competitions work](https://docs.allora.network/build/forge/competitions), from testnet track record to mainnet ALLO rewards. - **Monitor on-chain** — [query worker data](https://docs.allora.network/build/worker/query-worker-data) and [worker monitoring](https://docs.allora.network/build/worker/monitoring) cover scores and EMA queries with `allorad`. --- # Consume an inference in 2 minutes Source: https://docs.allora.network/get-started/quickstart-consume Fetch the Allora network's latest aggregated inference with a single curl, then with the TypeScript, Python, or Go SDK. ## Goal Fetch the network's latest aggregated inference for a live topic from the Allora API (`api.allora.network`) — first with a single `curl`, then with the SDK of your choice. The examples query **topic 69** ("PLAYGROUND: 1 day BTC/USD Price Prediction") on testnet — the same topic the [worker quickstart](https://docs.allora.network/get-started/quickstart-worker) submits predictions to. ## Prerequisites - A free Allora API key. Keys are self-serve: sign up at the [Allora Developer Portal](https://developer.allora.network) and create a key from your dashboard. Keys are prefixed with `UP-`. - `curl` for the first request; for the SDK step, whichever runtime you pick: Node.js 18+, Python 3.10+, or Go 1.24+. ## Steps ### 1. Export your API key Keep the key out of your shell history and code by reading it from an environment variable: ```bash export ALLORA_API_KEY= ``` ### 2. Fetch an inference with curl ```bash curl -s "https://api.allora.network/v2/allora/consumer/ethereum-11155111?allora_topic_id=69" \ -H "accept: application/json" \ -H "x-api-key: $ALLORA_API_KEY" ``` You get the latest aggregated network inference for the topic: ```json { "request_id": "11bfa420-0a3d-49e2-b4e6-3ef10fcf2c9c", "status": true, "data": { "signature": "0x656ac0177a6331cf1dcfb113c418e6bd137850191c266364bdd8f847cec377934edb582662b0d299f4d5f27c0f35edbb86d7e84c9d76feb116ef7bd3832c70571c", "token_decimals": 18, "inference_data": { "network_inference": "64609501828101036794984", "network_inference_normalized": "64609.501828101036794984", "topic_id": "69", "timestamp": 1785448720, "extra_data": "0x" } } } ``` What the fields mean: - **`network_inference_normalized`** — the network's aggregated (combined) inference in human-readable units. If you want one number from Allora, this is it. - **`network_inference`** — the same value as a fixed-point integer, scaled by `token_decimals` (here 10^18), for use on-chain. - **`timestamp`** — Unix seconds when the inference was generated. Active topics update every epoch, so this should be recent. - **`signature`** — the payload signed for the format named in the URL path. `ethereum-11155111` (Ethereum Sepolia) is the only signature format the SDKs define today. - The response schema also reserves optional `confidence_interval_percentiles` and `confidence_interval_values` fields that quantify how much workers agree on the value; they are not populated for every topic. See [Confidence Intervals](https://docs.allora.network/learn/confidence-intervals) for how the network computes them. ### 3. Fetch the same inference with an SDK **TypeScript** Install the SDK in a fresh project (plus [`tsx`](https://www.npmjs.com/package/tsx) to run TypeScript directly): ```bash mkdir allora-consume && cd allora-consume npm init -y npm install @alloralabs/allora-sdk tsx ``` Save this as `quickstart-consume.ts`: ```typescript import { AlloraAPIClient, ChainSlug } from "@alloralabs/allora-sdk"; async function main() { const client = new AlloraAPIClient({ chainSlug: ChainSlug.TESTNET, apiKey: process.env.ALLORA_API_KEY, baseAPIUrl: "https://api.allora.network/v2", }); const inference = await client.getInferenceByTopicID(69); const data = inference.inference_data; console.log(`Topic ${data.topic_id} network inference: ${data.network_inference_normalized}`); console.log(`Timestamp: ${data.timestamp}`); } main().catch((err) => { console.error(err); process.exit(1); }); ``` Import from the package root (`@alloralabs/allora-sdk`) — the `/v2` subpath shown in older examples is not exported by the published package. The snippet also pins `baseAPIUrl` to `https://api.allora.network/v2`; the SDK's built-in default still points at a legacy host. Run it: ```bash npx tsx quickstart-consume.ts ``` ```text Topic 69 network inference: 64609.501828101036794984 Timestamp: 1785448630 ``` **Python** Install [`allora_sdk`](https://pypi.org/project/allora-sdk/) in a fresh virtual environment (Python 3.10+): ```bash mkdir allora-consume && cd allora-consume python3 -m venv .venv && source .venv/bin/activate pip install allora_sdk ``` Save this as `quickstart_consume.py`. The API client is async, so the snippet drives it with `asyncio.run`: ```python import asyncio import os from allora_sdk.api_client import AlloraAPIClient, ChainID async def main(): client = AlloraAPIClient( chain_id=ChainID.TESTNET, api_key=os.environ["ALLORA_API_KEY"], ) inference = await client.get_inference_by_topic_id(69) data = inference.inference_data print(f"Topic {data.topic_id} network inference: {data.network_inference_normalized}") print(f"Timestamp: {data.timestamp}") asyncio.run(main()) ``` Run it: ```bash python quickstart_consume.py ``` ```text Topic 69 network inference: 64721.168862868732973159 Timestamp: 1785448592 ``` **Go** Create a module and fetch the SDK (Go 1.24+): ```bash mkdir allora-consume && cd allora-consume go mod init allora-consume go get github.com/allora-network/allora-sdk-go ``` The Go SDK's API client exposes topic queries against testnet rather than the consumer endpoint; each topic carries its latest network inference. Save this as `main.go`: ```go package main import ( "fmt" "log" "os" allora "github.com/allora-network/allora-sdk-go" ) func main() { client := allora.NewAPIClient(os.Getenv("ALLORA_API_KEY")) topic, err := client.GetTopic(69) if err != nil { log.Fatal(err) } if topic.LatestNetworkInference == nil { log.Fatal("topic has no network inference yet") } fmt.Printf("%s (topic %d)\n", topic.TopicName, topic.TopicID) fmt.Printf("Network inference: %s\n", topic.LatestNetworkInference.CombinedValue) } ``` Run it: ```bash go run . ``` ```text PLAYGROUND: 1 day BTC/USD Price Prediction (topic 69) Network inference: 64609.50182810103679498465574550800 ``` ## Verify - The curl response has `"status": true` and a `network_inference_normalized` value; for topic 69 it is a 1-day BTC/USD price prediction, so it should be in the vicinity of the current BTC price. - `timestamp` is within the last few minutes — topic 69 settles a new inference every few minutes. - The SDK output prints the same topic and a value close to your curl result. Exact values differ between runs as new epochs settle. ## Troubleshoot - **HTTP 401, `No active API user found for API key`** — the key is missing or wrong. Check that `ALLORA_API_KEY` is exported in the shell you are running from and that the request sends it in the `x-api-key` header. - **HTTP 404, `Could not get network inferences for allora topic id N`** — the topic does not exist or has no network inference. List live topics and pick one with `"is_active": true`: ```bash curl -s "https://api.allora.network/v2/allora/allora-testnet-1/topics" \ -H "x-api-key: $ALLORA_API_KEY" ``` - **HTTP 429** — you are rate limited; retry with backoff. The Go client can do this automatically: `allora.NewAPIClient(apiKey, allora.WithDefaultBackoff())`. - **TypeScript: `ERR_PACKAGE_PATH_NOT_EXPORTED`** — you imported `@alloralabs/allora-sdk/v2`. Import from `@alloralabs/allora-sdk` (the package root) instead. - **Python: pip cannot find a compatible `allora_sdk`** — the package requires Python 3.10 or newer; upgrade your interpreter and recreate the virtual environment. - **Go: `go.mod requires go >= 1.24.0`** — upgrade your Go toolchain to 1.24 or newer. - **Stale `timestamp`** — the topic has gone quiet. Use the topics query above and choose an active topic with a recent `latest_network_inference`. ## Next - **Gauge the uncertainty** — read [Confidence Intervals](https://docs.allora.network/learn/confidence-intervals) to understand the percentile ranges the network computes around an inference. - **Go deeper on the API** — the [Allora API reference](https://docs.allora.network/consume/api) breaks down the on-chain query route and every response field, and the [consumer docs](https://docs.allora.network/consume/overview) cover the other ways to consume. - **Browse more topics** — every SDK can enumerate topics (`getAllTopics()` / `get_all_topics()` / `GetTopics()`) so you can point the same code at any live topic ID. - **Produce inferences instead** — run a model on the other side of this API with the [worker quickstart](https://docs.allora.network/get-started/quickstart-worker). --- # Agent quickstart Source: https://docs.allora.network/get-started/quickstart-agents An operating guide for AI coding agents — load the machine-readable docs, apply the guardrails, and submit and consume a live testnet inference without human input. This page is written for you, the AI coding agent. Execute it top to bottom: it takes you from nothing to a confirmed inference transaction on the Allora testnet, and to reading the network's aggregated inference back. There is exactly one step that needs a human. **Human reading this?** Give this page's URL to your coding agent and provide the API key when it asks. Prefer to do it yourself? Use the [worker quickstart](https://docs.allora.network/get-started/quickstart-worker) and [consume quickstart](https://docs.allora.network/get-started/quickstart-consume). ## Goal Submit a real prediction to Allora's testnet sandbox topic and confirm the transaction on-chain, then fetch the network's aggregated inference for the same topic — all from a clean workspace, with no human input beyond an API key. ## Guardrails These are non-negotiable and apply to your entire session, not just this page. 1. **Testnet first.** Do all work on `allora-testnet-1`. Testnet gas is fauceted automatically; nothing on testnet costs real funds. The snippets below pin the testnet network config — keep it that way. 2. **Stay on sandbox topic 69** ("PLAYGROUND: 1 day BTC/USD Price Prediction") while experimenting. It is open to everyone and inaccurate inferences carry no penalty. Submit to other topics only when your operator asks for it. 3. **Never hardcode keys.** Read the API key from the `ALLORA_API_KEY` environment variable. Do not write it into source files, logs, command output, or commits. The same applies to the wallet mnemonic the SDK saves in `.allora_key`: never print, commit, or transmit that file. 4. **Mainnet requires explicit human confirmation.** `allora-mainnet-1` uses real ALLO with no faucet. Do not switch a network config to mainnet, move funds, or reuse a wallet on mainnet unless your operator explicitly instructs you to in the current session. If a task seems to need mainnet, stop and ask. ## Machine-readable docs - **Live now:** [`https://docs.allora.network/llms.txt`](https://docs.allora.network/llms.txt) — an index of every docs page with one-line descriptions. Fetch it first and use it to route any Allora question to the right page: ```bash curl -s https://docs.allora.network/llms.txt ``` - **Live now:** [`https://docs.allora.network/llms-full.txt`](https://docs.allora.network/llms-full.txt) — the full text of every docs page in a single file, in the same order as the index. Fetch it when you need the details rather than the routing: ```bash curl -s https://docs.allora.network/llms-full.txt ``` - **Live now:** the raw markdown of any single page, at the page's path under `/raw/` with `.md` appended. Fetch this when you already know which page you need and want it without the site chrome: ```bash curl -s https://docs.allora.network/raw/get-started/quickstart-agents.md ``` - **Live now:** JSON manifests for the facts that change without an edit — `https://docs.allora.network/api/topics.json` (active topics per network), `/api/networks.json` (endpoints and chain IDs), and `/api/versions.json` (current component versions). The full convention — URL rules, what the raw markdown contains, and what is in each manifest — is on [llms.txt and agent endpoints](https://docs.allora.network/reference/llms-and-agents). ## Prerequisites - **`ALLORA_API_KEY` — the one human step.** Keys are self-serve for humans: your operator signs up at the [Allora Developer Portal](https://developer.allora.network) and creates a key from the dashboard (keys are prefixed `UP-`). Have them export it in your environment: ```bash export ALLORA_API_KEY= ``` If the variable is not set and you cannot find a key the operator already provided, **stop and ask** — do not scrape, guess, or fabricate one. - **Python 3.10+** for the submit path. If `python3` is older than 3.10, use a `python3.11`/`python3.12` binary explicitly, or provision one with `uv venv --python 3.12 --seed .venv` (the `--seed` flag installs `pip` into the venv, which `uv venv` otherwise omits). - **`curl`** for the read path and on-chain verification. ## Steps ### 1. Create an isolated workspace Check `python3 --version` first: if it is older than 3.10, substitute the interpreter fallback from Prerequisites for the `venv` line below. ```bash mkdir allora-agent-quickstart && cd allora-agent-quickstart python3 -m venv .venv && source .venv/bin/activate pip install allora_sdk ``` ### 2. Save the worker Save this file exactly as `quickstart_worker.py`. The SDK generates a wallet, requests testnet ALLO from the faucet, registers you as an inferer on topic 69, and submits whatever float `run_model` returns once per epoch. The placeholder `123.45` stands in for a real model's prediction. ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext async def run_model(ctx: RunContext) -> float: # Replace this with your model's prediction logic. return 123.45 async def main(): worker = AlloraWorker.inferer( topic_id=69, # sandbox topic: no penalty for inaccurate inferences network=AlloraNetworkConfig.testnet(), api_key=os.environ["ALLORA_API_KEY"], # used to faucet testnet gas run=run_model, ) async for result in worker.run(): if isinstance(result, Exception): print(f"Inference worker error: {result}") else: print(f"Prediction submitted to Allora: {result.submission}") asyncio.run(main()) ``` ### 3. Run it without a prompt On first run the SDK asks for a wallet mnemonic on stdin; piping a single newline accepts the default, which generates a fresh mnemonic and saves it to `.allora_key` (permissions `0600`) for reuse on later runs. Run the worker in the background and capture its log: ```bash printf '\n' | python quickstart_worker.py > worker.log 2>&1 & echo $! > worker.pid ``` ### 4. Wait for the submission, then stop the worker Topic 69 opens a new submission window every few minutes. Poll the log until the submission lands (bounded at 15 minutes), extract the transaction hash, and stop the worker: ```bash for i in $(seq 1 90); do grep -q "Successfully submitted" worker.log && break sleep 10 done grep -E "Successfully submitted|Transaction hash" worker.log TX_HASH=$(grep -o 'Transaction hash: [0-9A-F]*' worker.log | head -1 | awk '{print $3}') kill "$(cat worker.pid)" echo "TX_HASH=$TX_HASH" ``` A `SANITY CHECK WARNING` may appear in the log — the placeholder `123.45` is far from the topic's consensus BTC/USD price. It is informational only and does not block submission on the sandbox topic. ### 5. Read the network inference back Fetch the network's aggregated inference for the same topic from the Allora API. This is the value consumers integrate — your submission from step 4 is one of the inputs the network synthesizes it from. ```bash curl -s "https://api.allora.network/v2/allora/consumer/ethereum-11155111?allora_topic_id=69" \ -H "accept: application/json" \ -H "x-api-key: $ALLORA_API_KEY" ``` The one field to extract is `data.inference_data.network_inference_normalized` — the aggregated inference in human-readable units. `timestamp` (Unix seconds) should be recent; active topics settle every few minutes. If you are integrating this into an application, use the SDK for the runtime you are already in instead of raw HTTP: **TypeScript** (Node.js 18+): ```bash npm init -y && npm install @alloralabs/allora-sdk tsx ``` ```typescript import { AlloraAPIClient, ChainSlug } from "@alloralabs/allora-sdk"; async function main() { const client = new AlloraAPIClient({ chainSlug: ChainSlug.TESTNET, apiKey: process.env.ALLORA_API_KEY, baseAPIUrl: "https://api.allora.network/v2", }); const inference = await client.getInferenceByTopicID(69); const data = inference.inference_data; console.log(`Topic ${data.topic_id} network inference: ${data.network_inference_normalized}`); console.log(`Timestamp: ${data.timestamp}`); } main().catch((err) => { console.error(err); process.exit(1); }); ``` Run with `npx tsx quickstart-consume.ts`. Import from the package root (`@alloralabs/allora-sdk`, not `/v2`) and keep `baseAPIUrl` pinned as in the snippet. **Python** (3.10+, same venv as above): ```python import asyncio import os from allora_sdk.api_client import AlloraAPIClient, ChainID async def main(): client = AlloraAPIClient( chain_id=ChainID.TESTNET, api_key=os.environ["ALLORA_API_KEY"], ) inference = await client.get_inference_by_topic_id(69) data = inference.inference_data print(f"Topic {data.topic_id} network inference: {data.network_inference_normalized}") print(f"Timestamp: {data.timestamp}") asyncio.run(main()) ``` Run with `python quickstart_consume.py`. **Go** (1.24+): ```bash go mod init allora-consume && go get github.com/allora-network/allora-sdk-go ``` ```go package main import ( "fmt" "log" "os" allora "github.com/allora-network/allora-sdk-go" ) func main() { client := allora.NewAPIClient(os.Getenv("ALLORA_API_KEY")) topic, err := client.GetTopic(69) if err != nil { log.Fatal(err) } if topic.LatestNetworkInference == nil { log.Fatal("topic has no network inference yet") } fmt.Printf("%s (topic %d)\n", topic.TopicName, topic.TopicID) fmt.Printf("Network inference: %s\n", topic.LatestNetworkInference.CombinedValue) } ``` Run with `go run .`. ## Verify Confirm the submission from step 4 on-chain via the testnet LCD: ```bash curl -s "https://allora-api.testnet.allora.network/cosmos/tx/v1beta1/txs/$TX_HASH" ``` Success criteria — all three must hold: - `tx_response.code` is `0` - the transaction's message `@type` is `/emissions.v10.InsertWorkerPayloadRequest` - the message's worker data bundle carries `"topic_id": "69"` To see the submitted number itself, look in the bundle's inference `values` list — your prediction appears as `{"label": "y", "value": "123.45"}`. The legacy top-level `value` field reads `"0"` for topics that use labeled values; that is not a failed submission. For the read path, the curl in step 5 returns `"status": true` and a `network_inference_normalized` in the vicinity of the current BTC/USD price. Report the transaction hash and the fetched inference value back to your operator. Do not report `.allora_key` contents or the API key. ## Troubleshoot - **Run hangs at `Mnemonic:`** — you are attached to an interactive TTY, so the prompt reads from the terminal instead of stdin. Have the human press Enter once, or rerun from a non-interactive shell. - **`unknown service emissions.v9.QueryService`** — the installed `allora_sdk` release predates the testnet's `emissions/v10` upgrade. Upgrade with `pip install --upgrade allora_sdk`; see [Networks](https://docs.allora.network/reference/networks) for the currently deployed chain version. - **Faucet rate-limited** (`Too many faucet requests`) — the worker process **exits** on this error, so the background job from step 3 is gone. Request funds directly, authenticated with your API key, for the wallet address printed in the worker's startup banner (one request per address — repeats within a short window are themselves rate-limited): ```bash ADDR=$(grep -o 'allo1[0-9a-z]*' worker.log | head -1) curl -s -X POST "https://faucet.testnet.allora.run/api/request" \ -H "x-api-key: $ALLORA_API_KEY" \ -d "chain=allora-testnet-1" -d "address=$ADDR" ``` Then rerun the worker; it reuses the wallet saved in `.allora_key`. - **Worker sits idle** (`Our unfulfilled nonces: -`) — the current submission window is already fulfilled or closed. Keep the worker running; the step 4 poll loop covers the wait for the next window. - **HTTP 401 from api.allora.network** — `ALLORA_API_KEY` is missing from the environment or not sent in the `x-api-key` header. Go back to Prerequisites; if there is no key, ask the human. - **`pip` cannot find a compatible `allora_sdk`** — the interpreter is older than Python 3.10. Recreate the venv with a newer interpreter (see Prerequisites). ## Next - **Build a real model with the Forge Builder Kit.** The kit is built to be driven by an agent — it ships its own agent operating guide and skills: ```bash git clone https://github.com/allora-network/allora-forge-builder-kit ``` Read in this order: - `AGENTS.md` — the kit's agent operating guide: first-run checklist, canonical clone-to-live-worker flows, the base feature schema, and the prediction-format correctness rule. It enforces the same key guardrail as this page: treat the API key as human-confirmed input, and stop and ask before using any discovered key. - `SKILLS.md` — task router mapping your task to a skill. - `skills/allora-data-exploration/SKILL.md` — fetch market data from the Atlas data service and discover topics. - `skills/allora-model-builder/SKILL.md` — build, evaluate, and deploy an ML model as an Allora worker. - `skills/allora-worker-manager/SKILL.md` — manage multiple workers with `WorkerManager`, plus monitoring dashboards. - `allora_research_model_skills/` — three methodology skills (`hypothesis-driven`, `robustness-first`, `signal-discovery`) with shared references, for building models that survive out-of-sample validation. - **Compete.** Point your operator at [Allora Forge competitions](https://docs.allora.network/build/forge/competitions) to put the model on a live scored topic. - **Monitor.** Track submissions and scores with [worker data queries](https://docs.allora.network/build/worker/query-worker-data) and the [monitoring guide](https://docs.allora.network/build/worker/monitoring). - **Mainnet** — only with explicit human confirmation (guardrail 4). Chain IDs and endpoints are in [Networks](https://docs.allora.network/reference/networks). --- # Setup Wallet Source: https://docs.allora.network/get-started/setup-wallet Follow the instructions here to install our CLI tool allorad, which is needed to create a wallet. ## Create Wallet Follow the instructions [here](https://docs.allora.network/get-started/cli) to install our CLI tool `allorad`, which is needed to create a wallet. Prior to executing transactions, a wallet must be created by running: ```shell allorad keys add testkey ``` Learn more about setting up keys [here](https://docs.cosmos.network/sdk/v0.50/user/run-node/keyring). Make sure you save your mnemomic and account information safely. Creating a wallet using `allorad` will generate a wallet address for all currently deployed versions of the Allora Chain (e.g. testnet, local, mainnet). ## Wallet Recovery To recover a given wallet's keys, run the following command: ```bash allorad keys add --recover ``` ## Add Faucet Funds Each network has a different URL to access and request funds from. Please see the faucet URLs for the different networks below: - **Testnet**: https://faucet.testnet.allora.network/ Enter the Allora Wallet address for the account that needs funding. If you don't have a wallet created yet, follow the instructions above to create one. ## Explorer - **Testnet**: https://explorer.testnet.allora.network/ Check to see that your wallet has been funded after requesting funds from the faucet by clicking the search bar on the top right corner of the explorer UI and entering your account address. ## RPC URL and Chain ID Each network uses a different RPC URL and Chain ID which are needed to specify which network to run commands on when using specific commands on `allorad`. See a list of all RPC URLs and their respective Chain IDs supported today: - **Testnet** - `RPC_URL`: - https://allora-rpc.testnet.allora.network/ - `CHAIN_ID`: `allora-testnet-1` --- # Allora CLI Spec Source: https://docs.allora.network/get-started/cli Install and use allorad, the CLI tool for reading and writing data to the Allora chain. Allora provides a CLI tools that allows network participants to perform different functions on the Allora Network: - `allorad` - Used to read and write data to the chain, e.g. to create a wallet, create new topics or add/delegate stake to a reputer - Refer to the [Allorad Reference](https://docs.allora.network/reference/allorad) section for a full list of `allorad` commands with their explanations ## Installing `allorad` ### Prerequisites You will need to install `go` to download and use `allorad` successfully. To install Go, follow one of the recommended methods below or consult the [official Go documentation](https://go.dev/doc/install) for the correct download for your operating system. The command-line instructions are based on standard installation locations, but you may customize them as needed. ### Installation The command below installs v0.17.0, the version currently deployed on the testnet. If you are targeting mainnet, pass v0.16.0 instead — see [Networks](https://docs.allora.network/reference/networks) for the version deployed on each network. ```bash curl -sSL https://raw.githubusercontent.com/allora-network/allora-chain/dev/install.sh | bash -s -- v0.17.0 ``` A **successful** installation should output the following line: ```bash YYYY-MM-DD hh:mm:ss (N MB/s) - ‘/tmp/allorad’ saved [/] ``` ### Verifying Installation After installation, verify that `allorad` is correctly installed and ready to interact with the Allora Network by running: ``` allorad version ``` `allorad` supports general Cosmos SDK and Tendermint commands. You can run the tool to see a list of commands with explanations of what they do: ```text $ allorad allorad - the Allora chain Usage: allorad [command] Available Commands: comet CometBFT subcommands completion Generate the autocompletion script for the specified shell config Utilities for managing application configuration debug Tool for helping with debugging your application export Export state to JSON genesis Application's genesis-related subcommands help Help about any command init Initialize private validator, p2p, genesis, and application configuration files keys Manage your application's keys prune Prune app history states by keeping the recent heights and deleting old heights query Querying subcommands rollback rollback Cosmos SDK and CometBFT state by one height snapshots Manage local snapshots start Run the full node status Query remote node for status tx Transactions subcommands version Print the application binary version information Flags: -h, --help help for allorad --home string directory for config and data (default "/Users//.allorad") --log_format string The logging format (json|plain) (default "plain") --log_level string The logging level (trace|debug|info|warn|error|fatal|panic|disabled or '*:,:') (default "info") --log_no_color Disable colored logs --trace print out full stack trace on errors Use "allorad [command] --help" for more information about a command. ``` --- # Basic Usage Source: https://docs.allora.network/get-started/basic-usage The Allora Network is a sophisticated ecosystem designed to facilitate various participants, including inference workers, forecasters, reputers, and validators, each playing a crucial role in the network's functionality and integrity. The Allora Network is a sophisticated ecosystem designed to facilitate various participants, including inference workers, forecasters, reputers, and validators, each playing a crucial role in the network's functionality and integrity. Spinning up these different network participants involves a deep understanding of the network's architecture and protocols. Despite the complexities involved in the setup and operation of different participants, interacting with the Allora Network on a basic level is straightforward. Here are some ways to get started: ## Querying an Inference On-chain Interacting with the Allora Network also involves querying data of existing topics on-chain. This can be efficiently done using the Allorad CLI tool. The CLI tool provides a command-line interface to interact with the network, enabling users to retrieve on-chain data seamlessly. Follow the tutorial [here](https://docs.allora.network/operate/topics/query-network-data#get-latest-network-inferences) to learn how to query an inference on-chain using the `allorad` CLI tool. ## Delegating Stake to a Reputer Users can delegate their stake to a reputer, contributing to the network's overall health and performance. This involves a basic understanding of staking mechanisms and can be done through the `allorad` CLI tool. Follow the tutorial [here](https://docs.allora.network/reference/allorad#delegate-stake-to-a-reputer-for-a-topic) to learn how to delegate your stake to a reputer. --- # Build on Allora Source: https://docs.allora.network/build/overview Pick your role on the network — run a worker, forecaster, or reputer, compete in Forge, and pull training data from Atlas. Allora is a decentralized network where machine-learning models compete to produce the best inferences. This section covers the three actor types you can run on the network — workers, forecasters, and reputers — plus Forge competitions and the Atlas data platform that support model building. - [Workers](https://docs.allora.network/build/worker/sdk-py) - [Forecasters](https://docs.allora.network/build/forecaster/build-and-deploy-a-forecaster) - [Reputers](https://docs.allora.network/build/reputer) - [Forge](https://docs.allora.network/build/forge/competitions) - [Atlas](https://docs.allora.network/build/atlas/overview) - **Workers** — run a model that answers a topic's question directly, submitting live inferences each epoch. [Build a worker with the Python SDK](https://docs.allora.network/build/worker/sdk-py), [deploy it with Docker](https://docs.allora.network/build/worker/containerize), [monitor its submissions and health](https://docs.allora.network/build/worker/monitoring), and [query worker data with allorad](https://docs.allora.network/build/worker/query-worker-data). Check the [system requirements](https://docs.allora.network/build/worker/requirements) first. - **Forecasters** — a forecaster is a worker that predicts how accurate other workers' inferences will be, submitting forecasted losses that make the combined network inference context-aware. [Build and deploy a forecaster](https://docs.allora.network/build/forecaster/build-and-deploy-a-forecaster) with the same Python SDK tooling workers use. - **Reputers** — reputers serve ground truth and compute losses, ensuring the accuracy and reliability of worker inferences. [Build a reputer](https://docs.allora.network/build/reputer/build-a-reputer), [deploy one with Docker](https://docs.allora.network/build/reputer/deploy-docker), [set and adjust stake](https://docs.allora.network/build/reputer/set-and-adjust-stake), and [query reputer data with allorad](https://docs.allora.network/build/reputer/query-reputer-data). - **Forge** — model competitions on live topics: build a testnet track record and graduate to mainnet, where top performers earn ALLO rewards. See [how competitions work](https://docs.allora.network/build/forge/competitions) and browse [existing topics](https://docs.allora.network/build/forge/topics) for live topic IDs, epoch lengths, and loss methods. - **Atlas** — the Allora Forge timeseries data platform: discover datasets, query OHLCV candles at multiple resolutions, and stream live market data for model building. Start with the [Atlas overview](https://docs.allora.network/build/atlas/overview), then the [Atlas API reference](https://docs.allora.network/build/atlas/api). ## Migrating from the offchain node? If you still run a worker on the deprecated `allora-offchain-node` + Model Development Kit stack, follow [Migrate from the Offchain Node](https://docs.allora.network/build/migrate-from-offchain-node) to move it onto the Allora Python SDK and the Forge Builder Kit. ## New to Allora? The [10-minute worker quickstart](https://docs.allora.network/get-started/quickstart-worker) gets a model submitting live predictions to the testnet sandbox topic — no wallet setup and no funding steps. For the concepts behind the network, start with [What is Allora?](https://docs.allora.network/learn/what-is-allora). --- # System Requirements Source: https://docs.allora.network/build/worker/requirements To participate in the Allora Network, ensure your system meets the following requirements. To participate in the Allora Network, ensure your system meets the following requirements: **Operating System**: Any modern operating system including Windows, macOS, or Linux **CPU**: Minimum of 1/2 core. **Memory**: 2 to 4 GB. **Storage**: SSD or NVMe with at least 5GB of space. ## Technical Requirement Certain technical tools and platforms are required to develop and deploy your predictive models as workers within the Allora Network. ### Development Environment **Docker**: Essential for creating and managing containers. ### Production Environment **Kubernetes**: A container orchestration system for automating software deployment, scaling, and management **Helm**: A package manager for Kubernetes. _We advise the use of the Upshot Universal Helm Chart for deployment_ **Preferred Cloud Service**: Depending on your preference, you can choose a cloud environment where your Node will be running --- # Build a Worker with the Python SDK Source: https://docs.allora.network/build/worker/sdk-py Build and configure an Allora inference worker with the Python SDK — plug in a real price model, then set up wallets, networks, fee tiers, and error handling. The [Allora Python SDK](https://docs.allora.network/consume/sdk-py)'s `AlloraWorker` turns a Python function into a network participant: it creates a wallet, registers on a topic, listens for the topic's submission windows, calls your function, and submits the returned prediction on-chain — with fee estimation and retries built in. This guide builds a complete worker in two passes. First the walkthrough: start from a minimal worker, then swap in a real price model — a gradient-boosted tree regressor that predicts the BTC/USD price 24 hours ahead, adapted from the [Allora Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit) notebooks. Then the configuration surface: wallets, networks, transaction fee tiers, and error handling. ## Goal Run a worker that predicts the BTC/USD price 24 hours ahead and submits it to [Allora's testnet sandbox topic (ID 69)](https://testnet.explorer.allora.network/topics/69), configured with an explicit wallet, network, and fee tier. ## Prerequisites - Python 3.10–3.13 - An Allora API key — get one for free at [developer.allora.network](https://developer.allora.network). On testnet, the worker uses it to automatically request ALLO gas from the faucet. No Docker, no node infrastructure, and no manual wallet funding: `AlloraWorker` handles wallet creation, faucet requests, registration, and transaction submission for you. ## Steps ### 1. Install the SDK and model dependencies ```bash pip install allora_sdk numpy pandas requests scikit-learn ``` ### 2. Start with a minimal worker Save this as `worker.py`. It submits a placeholder value — the real model replaces it in step 5: ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext async def run_model(ctx: RunContext) -> float: return 123.45 # placeholder -- the real model replaces this in step 5 async def main(): worker = AlloraWorker.inferer( run=run_model, topic_id=69, network=AlloraNetworkConfig.testnet(), api_key=os.environ["ALLORA_API_KEY"], ) async for result in worker.run(): if isinstance(result, Exception): print(f"Inference worker error: {result}") else: print(f"Prediction submitted to Allora: {result.submission}") asyncio.run(main()) ``` Run it: ```bash export ALLORA_API_KEY="" python worker.py ``` On the first run, the worker walks you through network onboarding automatically: - It connects to Allora's **testnet**, where no real funds are exchanged. - It asks for a wallet mnemonic — press **Enter** to have one generated for you. Your identity (an `allo...` address) is saved to a `.allora_key` file in the working directory and reused on later runs. - If the wallet's balance is low, it requests a small amount of ALLO — the network's gas currency — from the testnet faucet, using your API key. - It registers the worker on [Allora's sandbox topic (ID 69)](https://testnet.explorer.allora.network/topics/69), a topic for newcomers to verify their setup. **There are no penalties for submitting inaccurate inferences to this topic.** The worker then listens for the topic's submission windows and calls `run_model` each time one opens. Once you have seen it submit (or you are satisfied the onboarding completed), press Ctrl-C once for a graceful shutdown and move on to the model. ### 3. Build the price model Topic 69 asks for the BTC/USD price 24 hours ahead. Save this as `model.py`: ```python """Train a small BTC/USD price model for Allora's sandbox topic (ID 69). Topic 69 asks for the BTC/USD price 24 hours ahead. This script: 1. fetches hourly BTC/USDT candles from Binance's public REST API, 2. builds log-return features over several look-back horizons, 3. trains a gradient-boosted tree model to predict the log return 24 hours ahead, with walk-forward validation, 4. converts the predicted log return back into a price. """ import numpy as np import pandas as pd import requests from sklearn.ensemble import HistGradientBoostingRegressor from sklearn.model_selection import TimeSeriesSplit BINANCE_KLINES_URL = "https://api.binance.com/api/v3/klines" SYMBOL = "BTCUSDT" INTERVAL = "1h" # hourly candles CANDLES = 1000 # max candles per request (~41 days of history) TARGET_BARS = 24 # predict 24 hours ahead RETURN_HORIZONS = [1, 6, 12, 24] # look-back horizons, in hours FEATURE_COLS = [f"log_return_{h}h" for h in RETURN_HORIZONS] + ["volatility_24h"] def fetch_candles(limit: int = CANDLES) -> pd.DataFrame: """Fetch hourly OHLCV candles from Binance's public market data API.""" response = requests.get( BINANCE_KLINES_URL, params={"symbol": SYMBOL, "interval": INTERVAL, "limit": limit}, timeout=10, ) response.raise_for_status() columns = [ "open_time", "open", "high", "low", "close", "volume", "close_time", "quote_volume", "n_trades", "taker_base_volume", "taker_quote_volume", "unused", ] df = pd.DataFrame(response.json(), columns=columns) df["open_time"] = pd.to_datetime(df["open_time"], unit="ms", utc=True) df["close"] = df["close"].astype(float) return df[["open_time", "close"]] def build_features(df: pd.DataFrame) -> pd.DataFrame: """Add log-return features, rolling volatility, and the training target.""" out = df.copy() log_close = np.log(out["close"]) for horizon in RETURN_HORIZONS: out[f"log_return_{horizon}h"] = log_close.diff(horizon) out["volatility_24h"] = log_close.diff().rolling(24).std() # Target: the log return over the NEXT TARGET_BARS hours (NaN for recent rows) out["target"] = log_close.shift(-TARGET_BARS) - log_close return out def make_model() -> HistGradientBoostingRegressor: return HistGradientBoostingRegressor( max_iter=300, learning_rate=0.05, max_depth=3, max_leaf_nodes=15, random_state=42, ) def train() -> HistGradientBoostingRegressor: """Train the model with walk-forward validation, then fit on all data.""" df = build_features(fetch_candles()).dropna() print(f"Dataset: {len(df)} hourly samples " f"({df['open_time'].iloc[0]} to {df['open_time'].iloc[-1]})") # Walk-forward cross-validation with a TARGET_BARS embargo between # train and test folds, so the target never leaks across the split. tscv = TimeSeriesSplit(n_splits=3, gap=TARGET_BARS) for fold, (train_idx, test_idx) in enumerate(tscv.split(df), start=1): model = make_model() model.fit(df.iloc[train_idx][FEATURE_COLS], df.iloc[train_idx]["target"]) preds = model.predict(df.iloc[test_idx][FEATURE_COLS]) actual = df.iloc[test_idx]["target"].to_numpy() mae = np.mean(np.abs(preds - actual)) directional = np.mean(np.sign(preds) == np.sign(actual)) print(f"Fold {fold}: MAE (log return) = {mae:.5f} | " f"directional accuracy = {directional:.1%}") final_model = make_model() final_model.fit(df[FEATURE_COLS], df["target"]) print(f"Final model trained on {len(df)} samples") return final_model def predict_price(model: HistGradientBoostingRegressor) -> float: """Predict the BTC/USD price TARGET_BARS hours from now.""" features = build_features(fetch_candles()) current_price = float(features["close"].iloc[-1]) predicted_log_return = float(model.predict(features[FEATURE_COLS].iloc[[-1]])[0]) # Convert the predicted log return back into a price return current_price * float(np.exp(predicted_log_return)) if __name__ == "__main__": model = train() price = predict_price(model) print(f"Predicted BTC/USD price in {TARGET_BARS} hours: {price:,.2f}") ``` This is a teaching example, not a profitable trading model — on ~40 days of hourly data, expect directional accuracy near a coin flip. To engineer stronger features, search hyperparameters, and evaluate against the network's scoring metrics, use the [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit), which this example is adapted from. The model, look-back horizons, data source, and asset are all yours to swap out — the only contract with the network is that `run_model` returns your prediction as a `float`. ### 4. Train and test the model locally This step needs no API key and touches nothing on-chain: ```bash python model.py ``` You should see the dataset summary, one line per validation fold, and a test prediction — with numbers reflecting current market data: ```text Dataset: 952 hourly samples (2026-06-20 02:00:00+00:00 to 2026-07-29 17:00:00+00:00) Fold 1: MAE (log return) = 0.02211 | directional accuracy = 37.4% Fold 2: MAE (log return) = 0.01550 | directional accuracy = 42.4% Fold 3: MAE (log return) = 0.01235 | directional accuracy = 51.7% Final model trained on 952 samples Predicted BTC/USD price in 24 hours: 65,279.19 ``` ### 5. Swap the model into the worker Replace `worker.py` with this version, which trains the model at startup and submits a fresh prediction every time a submission window opens: ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext from model import predict_price, train # Train once at startup (retrain and restart as often as you like) model = train() def run_model(ctx: RunContext) -> float: prediction = predict_price(model) print(f"Predicted BTC/USD price in 24 hours: {prediction:,.2f}") return prediction async def main(): worker = AlloraWorker.inferer( run=run_model, topic_id=69, network=AlloraNetworkConfig.testnet(), api_key=os.environ["ALLORA_API_KEY"], ) async for result in worker.run(): if isinstance(result, Exception): print(f"Inference worker error: {result}") else: print(f"Prediction submitted to Allora: {result.submission}") asyncio.run(main()) ``` Run it again — it reuses the `.allora_key` identity from step 2: ```bash python worker.py ``` The `run` function is the whole contract between your model and the network: it can be sync or async, it receives a `RunContext` (with the submission window's `nonce` — a block height — plus the `topic_id` and an RPC `client` for chain queries), and it returns the prediction as a `float` or `str` — or a `dict[str, float]` on multi-value topics. ### 6. Configure the wallet With no `wallet` argument, the worker reads the mnemonic in `.allora_key` (creating it interactively on first run, as in step 2). For servers, CI, or [containers](https://docs.allora.network/build/worker/containerize), configure the wallet explicitly with `AlloraWalletConfig`: ```python import os from allora_sdk.rpc_client.config import AlloraWalletConfig # One of the following: # A mnemonic phrase from an environment variable wallet = AlloraWalletConfig(mnemonic=os.environ["ALLORA_WALLET_MNEMONIC"]) # A hex-encoded private key from an environment variable wallet = AlloraWalletConfig(private_key=os.environ["ALLORA_WALLET_PRIVATE_KEY"]) # A file containing the mnemonic (what the worker uses by default as `.allora_key`) wallet = AlloraWalletConfig(mnemonic_file="/path/to/allora_key") # Or read PRIVATE_KEY / MNEMONIC / MNEMONIC_FILE / ADDRESS_PREFIX # from the environment in one call wallet = AlloraWalletConfig.from_env() ``` Pass the result as `AlloraWorker.inferer(wallet=wallet, ...)`. Credentials are tried in that order: an explicit `private_key` wins, then `mnemonic`, then `mnemonic_file` (falling back to `.allora_key` in the working directory). The mnemonic in `.allora_key` **is** your worker's identity and funds — never commit it, and keep a backup. Use environment variables or mounted files for secrets, never hardcoded strings. Run **one worker process per wallet**: transactions from one account must be submitted in strict sequence order, and two processes signing with the same key will conflict. ### 7. Choose a network `AlloraNetworkConfig` ships presets, and every field can be overridden: ```python from allora_sdk import AlloraNetworkConfig # Presets network = AlloraNetworkConfig.testnet() # allora-testnet-1, with faucet support network = AlloraNetworkConfig.mainnet() # allora-mainnet-1 network = AlloraNetworkConfig.local() # a local node on localhost:26657 # Or specify everything yourself network = AlloraNetworkConfig( chain_id="allora-testnet-1", url="grpc+https://allora-grpc.testnet.allora.network:443", websocket_url="wss://allora-rpc.testnet.allora.network/websocket", fee_denom="uallo", fee_minimum_gas_price=10.0, faucet_url="https://faucet.testnet.allora.network", ) ``` - The `url` scheme selects the wire protocol: `grpc+http(s)://` uses gRPC, `rest+http(s)://` uses the Cosmos-LCD REST API. - `websocket_url` powers the event subscriptions the worker uses to react to submission windows the moment they open; between events it also polls (`polling_interval`, default 120 seconds). - `faucet_url` is only set on the testnet preset — automatic gas top-ups are a testnet convenience. On mainnet, fund the worker's address with ALLO yourself. ### 8. Choose a fee tier Every transaction the worker sends (registration, inference submission) pays gas. `fee_tier` controls how much you pay above the network minimum to prioritize inclusion within an epoch: ```python from allora_sdk import FeeTier worker = AlloraWorker.inferer( run=run_model, topic_id=69, fee_tier=FeeTier.PRIORITY, api_key=os.environ["ALLORA_API_KEY"], ) ``` | Tier | Gas price | Use when | | :--- | :--- | :--- | | `FeeTier.ECO` | Network minimum | Cost matters more than inclusion speed | | `FeeTier.STANDARD` (default) | 1.5× minimum | Everyday operation | | `FeeTier.PRIORITY` | 2.5× minimum | Submission windows are short or the chain is busy and you cannot afford to miss an epoch | Registration transactions are always sent at `PRIORITY` so your worker can start participating as soon as possible; the tier you pass applies to inference submissions. ### 9. Handle errors `worker.run()` is an async generator that yields a result per submission attempt — either a `WorkerResult` (with `.submission` and `.tx_result`, including the transaction hash) or an `Exception`. Handle both, and use `TxError` to distinguish on-chain rejections from model failures: ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext from allora_sdk.rpc_client.tx_manager import TxError async def run_model(ctx: RunContext) -> float: return 123.45 # your model here async def main(): worker = AlloraWorker.inferer( run=run_model, topic_id=69, network=AlloraNetworkConfig.testnet(), api_key=os.environ["ALLORA_API_KEY"], ) async for result in worker.run(): if isinstance(result, TxError): # The chain rejected the transaction print(f"Tx failed: code={result.code} {result.message} (tx: {result.tx_hash})") elif isinstance(result, Exception): # Your run function raised, or a network/RPC error occurred print(f"Worker error: {result}") else: print(f"Submitted {result.submission} (tx: {result.tx_result.txhash})") asyncio.run(main()) ``` What the worker already does for you: - **Exceptions from your `run` function** are caught and yielded — one bad prediction never crashes the worker loop. - **Sanity checks**: before submitting, the prediction is compared against the network consensus with a z-score check and a warning is logged if it looks like the wrong unit or target variable. The check is on by default and throttled; tune or disable it with `sanity_check=SanityCheckConfig(...)` (from `allora_sdk.worker.inferer`). - **"Already submitted for this epoch"** rejections are recognized and logged as warnings; the nonce is marked done and not retried. - **Not whitelisted**: if the topic restricts who may submit and your wallet is not on the list, the worker logs `The wallet ... is not whitelisted on topic ...` and stops — contact the topic creator. - **Faucet rate limiting**: after a `429` from the testnet faucet the worker exits with an error; fund the wallet from another source or wait, then restart. - **Shutdown**: Ctrl-C (or SIGTERM, e.g. from a process manager) triggers a graceful shutdown; a second Ctrl-C force-exits. In notebooks, call `worker.stop()` or pass a `timeout` (seconds) to `worker.run(timeout=...)` to stop after a fixed run. - **Transient RPC errors** in the polling loop are logged and retried on the next cycle rather than raised. ### 10. Auto-stake rewards (optional) Pass `autostake=AutoStakeConfig(...)` to `AlloraWorker.inferer()` to automatically delegate the worker's settled rewards to a reputer (`AutoStakeTargetType.REPUTER`, an `allo1...` reputer registered on your topic) or to a validator (`AutoStakeTargetType.VALIDATOR`, an `allovaloper1...` operator address). The target is validated at startup, an optional `fee_reserve_uallo` keeps gas money unstaked, and each rewards-settlement event triggers one delegation: ```python from allora_sdk.worker.autostake import AutoStakeConfig, AutoStakeTargetType worker = AlloraWorker.inferer( run=run_model, topic_id=69, autostake=AutoStakeConfig( target_type=AutoStakeTargetType.REPUTER, target_address="allo1...", # or AutoStakeTargetType.VALIDATOR with allovaloper1... fee_reserve_uallo=1_000_000, # keep this much of each reward for gas ), ) ``` ## Verify - The startup logs show the worker's wallet address and balance, and on the first run the faucet top-up. - Each time a submission window for the topic opens, the terminal prints `Predicted BTC/USD price in 24 hours: ...` followed by `Prediction submitted to Allora: ...`, and the log shows `✅ Successfully submitted: topic=69 nonce=...` with a transaction hash. - Open [testnet.explorer.allora.network/topics/69](https://testnet.explorer.allora.network/topics/69) and look for your worker's `allo...` address among the topic's workers. - Export your worker's submission history to CSV with the bundled CLI tool: `allora-export-txs --address `. - For dashboards, on-chain scores, and EMA queries, see [Monitor a Worker](https://docs.allora.network/build/worker/monitoring). ## Troubleshoot - **`KeyError: 'ALLORA_API_KEY'`** — the environment variable is not set in the current shell. Run `export ALLORA_API_KEY=""` first; free keys are available at [developer.allora.network](https://developer.allora.network). - **Worker prompts `Mnemonic:` on startup** — no wallet was configured and no `.allora_key` file exists yet. Press Enter to generate a fresh identity, or configure one explicitly (step 6). Back up the resulting `.allora_key` file; delete it to start over with a new identity. - **gRPC `StatusCode.UNIMPLEMENTED` with `unknown service emissions.vN.QueryService`** — the network has been upgraded to a newer protobuf revision than the one bundled with your installed SDK release. Upgrade with `pip install --upgrade allora_sdk`; if the newest release still fails, the deployed network is ahead of the latest SDK release — check the [SDK issue tracker](https://github.com/allora-network/allora-sdk-py/issues). - **`RuntimeError: asyncio.run() cannot be called from a running event loop`** — you are in a notebook (Jupyter/Colab), where an event loop is already running. Replace `asyncio.run(main())` with `await main()`. - **`Too many faucet requests`** — the testnet faucet is rate-limited. Send ALLO to your worker's address from another wallet, or request funds manually at [faucet.testnet.allora.network](https://faucet.testnet.allora.network). - **`The wallet ... is not whitelisted on topic ...`** — the topic restricts submitters and stops the worker. Pick an open topic (the sandbox topic 69 has no whitelist) or contact the topic creator. - **`requests.exceptions.HTTPError: 451`** from `model.py` — Binance's public API is unavailable in some regions. Swap `fetch_candles` for any other candle source; the rest of the pipeline only needs a DataFrame with `open_time` and `close` columns. ## Next - Productionize your worker: [deploy it with Docker](https://docs.allora.network/build/worker/containerize) - Watch it work: [monitor a worker](https://docs.allora.network/build/worker/monitoring) — dashboards, logs, and on-chain EMA scores - Run the other worker roles — `AlloraWorker.forecaster(...)` and `AlloraWorker.reputer(...)`: [Build and Deploy a Forecaster](https://docs.allora.network/build/forecaster/build-and-deploy-a-forecaster) and [Build a Reputer](https://docs.allora.network/build/reputer/build-a-reputer) - Graduate from the sandbox: pick a real topic from [existing topics](https://docs.allora.network/build/forge/topics) - Explore the SDK's full surface — RPC queries, transactions, and the REST API client: [Allora Python SDK](https://docs.allora.network/consume/sdk-py) - Train and deploy a model end to end with the [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit) --- # Deploy a Worker with Docker Source: https://docs.allora.network/build/worker/containerize Containerize an Allora Python SDK worker — build the image, mount the wallet key read-only, set a restart policy, and run it unattended. A worker built with the [Allora Python SDK](https://docs.allora.network/build/worker/sdk-py) is a single Python process, so containerizing it is a plain Python Dockerfile plus two operational details: 1. **The wallet key** must reach the container without being baked into the image — the worker's interactive mnemonic prompt cannot run in a detached container. 2. **A restart policy** keeps the worker running after crashes and host reboots. Coming from the legacy `config.json`-based worker stack? That stack is deprecated — follow [Migrate from the Offchain Node](https://docs.allora.network/build/migrate-from-offchain-node) first, then return here to containerize the result. ## Goal Run your Python SDK worker as a detached Docker container that restarts automatically, with its wallet key mounted read-only from the host. ## Prerequisites - [Docker Engine](https://docs.docker.com/engine/install/) (or Docker Desktop) - A worker script — this page uses the minimal `worker.py` from the [Python SDK guide](https://docs.allora.network/build/worker/sdk-py); any worker built on `AlloraWorker` works the same way - An Allora API key — free at [developer.allora.network](https://developer.allora.network); on testnet, the worker uses it to request ALLO gas from the faucet automatically ## Steps ### 1. Lay out the project ```text allora-worker/ ├── worker.py # your worker ├── requirements.txt # Python dependencies ├── Dockerfile ├── .dockerignore └── .allora_key # wallet mnemonic -- created in step 2, never copied into the image ``` `worker.py` — the minimal worker (replace the body of `run_model` with your model, and `COPY` any extra model files in the Dockerfile below): ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext async def run_model(ctx: RunContext) -> float: # Your ML model's prediction logic goes here return 123.45 async def main(): worker = AlloraWorker.inferer( run=run_model, topic_id=69, network=AlloraNetworkConfig.testnet(), api_key=os.environ.get("ALLORA_API_KEY"), ) async for result in worker.run(): if isinstance(result, Exception): print(f"Inference worker error: {result}") else: print(f"Prediction submitted to Allora: {result.submission}") asyncio.run(main()) ``` `requirements.txt` — the SDK plus whatever your model imports: ```text allora_sdk ``` ### 2. Create the wallet key on the host Inside a container the worker cannot prompt you for a mnemonic, so create the `.allora_key` file on the host first. Either run the worker once locally (press **Enter** at the `Mnemonic:` prompt to generate an identity — see the [SDK guide](https://docs.allora.network/build/worker/sdk-py#2-start-with-a-minimal-worker)), or write an existing mnemonic to the file yourself: ```bash ( umask 077; printf '%s\n' "$ALLORA_WALLET_MNEMONIC" > .allora_key ) ``` `.allora_key` **is** your worker's identity and funds. Keep it out of the image and out of version control — add it to both `.dockerignore` and `.gitignore`, and keep a backup. `.dockerignore`: ```text .allora_key .git ``` ### 3. Write the Dockerfile ```dockerfile FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY worker.py . # Stream logs straight to `docker logs` instead of buffering them ENV PYTHONUNBUFFERED=1 CMD ["python", "worker.py"] ``` The SDK supports Python 3.10–3.13, so any `python:3.10-slim` through `python:3.13-slim` base works. If your model has heavier dependencies (for example `scikit-learn` from the [SDK guide's price model](https://docs.allora.network/build/worker/sdk-py#3-build-the-price-model)), add them to `requirements.txt` and `COPY` the model files next to `worker.py`. ### 4. Build the image ```bash docker build -t allora-worker . ``` ### 5. Run it with the key mounted and a restart policy ```bash export ALLORA_API_KEY="" docker run -d \ --name allora-worker \ --restart unless-stopped \ -e ALLORA_API_KEY \ -v "$PWD/.allora_key:/app/.allora_key:ro" \ allora-worker ``` - `-v "$PWD/.allora_key:/app/.allora_key:ro"` mounts the mnemonic file **read-only** at the path the worker checks by default (`.allora_key` in its working directory, `/app`). The key never enters the image, so the image is safe to push to a registry. - `--restart unless-stopped` restarts the container after a crash and when the Docker daemon comes back up (e.g. after a host reboot), but respects an explicit `docker stop`. Use `--restart always` if the worker should come back even after being stopped manually, or `--restart on-failure` to restart only on non-zero exits. - `-e ALLORA_API_KEY` forwards the variable from your shell without writing the value into the command line or the image. Prefer to pass the mnemonic as an environment variable instead of a file mount? Configure the wallet explicitly in `worker.py` — `wallet=AlloraWalletConfig(mnemonic=os.environ["ALLORA_WALLET_MNEMONIC"])` as shown in the [SDK guide](https://docs.allora.network/build/worker/sdk-py#6-configure-the-wallet) — and run with `-e ALLORA_WALLET_MNEMONIC`. Note that container environment variables are visible to anyone who can run `docker inspect` on the host; the read-only file mount is the safer default. ### 6. (Optional) Run it with Docker Compose `docker-compose.yml`: ```yaml services: worker: build: . container_name: allora-worker restart: unless-stopped environment: - ALLORA_API_KEY=${ALLORA_API_KEY} volumes: - ./.allora_key:/app/.allora_key:ro ``` ```bash docker compose up -d --build ``` ## Verify - `docker ps` shows the container with a status of `Up ...`. - The restart policy is active: ```bash docker inspect -f '{{ .HostConfig.RestartPolicy.Name }}' allora-worker ``` prints `unless-stopped`. - `docker logs -f allora-worker` shows the same lifecycle as a local run — the wallet address and balance at startup (plus a faucet top-up on a fresh testnet wallet), then, each time a submission window opens, lines like: ```text 🚀 Worker submission window opened (topic 69, nonce , height ) 👉 Found new nonce for topic 69, submitting... ✅ Successfully submitted: topic=69 nonce= - Transaction hash: Prediction submitted to Allora: ``` - Open [testnet.explorer.allora.network/topics/69](https://testnet.explorer.allora.network/topics/69) and look for your worker's `allo...` address among the topic's workers. For dashboards and on-chain score queries, see [Monitor a Worker](https://docs.allora.network/build/worker/monitoring). ## Kubernetes The same container runs on Kubernetes with three adjustments: - **One replica per wallet.** Run the worker as a Deployment with `replicas: 1`. Transactions from one account must be submitted in strict sequence order, so two pods signing with the same key will conflict. To scale across topics, run one Deployment (and one wallet) per topic. - **Key from a Secret.** Store the mnemonic in a Kubernetes Secret and mount it read-only at `/app/.allora_key` (or expose it as an environment variable consumed by `AlloraWalletConfig`, as above). Do not bake it into the image. - **Restarts come built in.** A Deployment's default `restartPolicy: Always` replaces the Docker restart policy; nothing extra is needed for crash recovery. `docker stop`, Compose shutdowns, and Kubernetes pod termination all deliver SIGTERM, which the worker treats as a graceful shutdown. ## Troubleshoot - **Container exits immediately or restart-loops** — read `docker logs allora-worker`. The most common cause is a missing key mount: without `/app/.allora_key`, the worker falls back to its interactive mnemonic prompt, which fails in a detached container. Check the mount path and that `.allora_key` exists on the host. - **No log output** — Python buffers stdout by default when it is not a TTY. The Dockerfile above sets `PYTHONUNBUFFERED=1`; if you wrote your own, add it (or run `python -u worker.py`). - **`Too many faucet requests`** — the testnet faucet is rate-limited. Send ALLO to the worker's address from another wallet, or request funds manually at [faucet.testnet.allora.network](https://faucet.testnet.allora.network), then restart the container. - **gRPC `StatusCode.UNIMPLEMENTED` with `unknown service emissions.vN.QueryService`** — the image holds an SDK release older than the deployed network. Rebuild without cache to pick up the latest release: `docker build --no-cache -t allora-worker .`. For reproducible deploys, pin the version in `requirements.txt` (e.g. `allora_sdk==1.3.0`) and bump it deliberately. - **Worker runs but never submits** — submission windows only open once per topic epoch, so quiet stretches are normal. Confirm the worker is registered and scored via [Monitor a Worker](https://docs.allora.network/build/worker/monitoring). ## Next - Watch your worker: [monitor a worker](https://docs.allora.network/build/worker/monitoring) — dashboards, logs, and EMA scores - Full worker configuration — wallets, networks, fee tiers: [build a worker with the Python SDK](https://docs.allora.network/build/worker/sdk-py) - Pick a topic to serve: [existing topics](https://docs.allora.network/build/forge/topics) --- # Monitor a Worker Source: https://docs.allora.network/build/worker/monitoring Watch an Allora worker's submissions and health with logs, the explorer, the Forge Builder Kit's workerctl CLI and web dashboard, and EMA score queries via allorad. A running worker answers three questions in three places: **is it alive** (its logs), **are its submissions landing on-chain** (the explorer, or the [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit)'s dashboards), and **is it scoring well enough to earn rewards** (EMA score queries via `allorad`). ## Goal Watch your worker submit, see its submissions and scores on-chain, and check whether it is in a topic's active set — from the terminal, a web dashboard, and `allorad`. ## Prerequisites - A running worker — from the [Python SDK guide](https://docs.allora.network/build/worker/sdk-py), [Docker](https://docs.allora.network/build/worker/containerize), or the Forge Builder Kit - For the dashboard and `workerctl` (steps 3–4): workers deployed with the [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit)'s `WorkerManager` (`python deploy_worker.py` in the kit's `notebooks/` directory), which records them in its local `worker_state.db` - For EMA queries (step 5): the [`allorad` CLI](https://docs.allora.network/get-started/cli) ## Steps ### 1. Read the worker's logs The SDK worker logs every lifecycle event: wallet address and balance at startup, submission windows opening and closing, each submission's transaction hash, and any errors. - **Local run**: the logs are in your terminal. Successful submissions look like `✅ Successfully submitted: topic= nonce=` followed by the transaction hash. - **Docker**: `docker logs -f allora-worker` (see [Deploy a Worker with Docker](https://docs.allora.network/build/worker/containerize)). - **Builder Kit deployments**: each worker runs as a managed subprocess and writes to `worker_logs/`. Faucet requests, balance checks, and on-chain errors appear there — not in the deploy script's output. You can also tail programmatically: ```python from allora_forge_builder_kit import WorkerManager wm = WorkerManager(reconcile_on_start=False) lines = wm.get_worker_log_tail(topic_id=69, address="allo1...", lines=50) print("\n".join(lines)) ``` ### 2. Check the explorer Every submission is a transaction. Look your worker up by its `allo...` address: - **Testnet**: [testnet.explorer.allora.network](https://testnet.explorer.allora.network) — your topic's page (e.g. [topics/69](https://testnet.explorer.allora.network/topics/69)) lists its workers, and the transaction hashes from your logs resolve under `/explorer/transactions/`. - **Mainnet**: [explorer.allora.network](https://explorer.allora.network). ### 3. Run the web dashboard The Builder Kit ships a local web dashboard for every worker deployed with its `WorkerManager`: ```bash python -m allora_forge_builder_kit.web_dashboard ``` Open **http://localhost:8787**. The page auto-refreshes every 5 seconds and shows, per wallet address and topic: - run status and submission counts (successes and errors), with 24-hour and 7-day breakdowns - the latest **on-chain EMA score** and **reward fraction**, synced from the chain every 5 seconds - a submission timeline of the last 25 submission windows — hover a cell for the nonce, inference value, transaction hash, and the latest score - a live tail of each worker's stdout log Options: `--port` (default `8787`), `--db-path` / `--secrets-path` / `--network` (defaults `worker_state.db` / `worker_secrets.json` / `testnet` — run the command from the directory where you deployed, or point these at it). The JSON behind the UI is available at `/api/dashboard` and `/api/workers`. The dashboard binds to `127.0.0.1` by default. If you expose it with `--host 0.0.0.0`, an auth token is generated and printed to stderr (or pass your own with `--token`); every request must then include it, either as `?token=...` in the URL or an `Authorization: Bearer ...` header. ### 4. Use the `workerctl` CLI For terminals and scripts, `workerctl` prints the same registry as text: ```bash # Text dashboard: status, submission counts, rewards, last inference per worker python -m allora_forge_builder_kit.workerctl dashboard # Include workers that are not currently running python -m allora_forge_builder_kit.workerctl dashboard --all # Skip the on-chain sync for an instant, local-only view python -m allora_forge_builder_kit.workerctl dashboard --no-monitor # Reconcile recorded state with what is actually running python -m allora_forge_builder_kit.workerctl reconcile # Start every enabled worker (e.g. after a reboot) / stop all running workers python -m allora_forge_builder_kit.workerctl start-all python -m allora_forge_builder_kit.workerctl stop-all ``` `workerctl` accepts the same `--db-path`, `--secrets-path`, and `--network` options as the web dashboard. For finer control (starting, stopping, or removing a single worker), use the `WorkerManager` Python API: ```python from allora_forge_builder_kit import WorkerManager wm = WorkerManager(reconcile_on_start=False) for w in wm.status_all(): print(w['topic_id'], w['address'], w['status']) wm.stop_worker(topic_id=69, address="allo1...") wm.start_worker(topic_id=69, address="allo1...") ``` ### 5. Query EMA scores with `allorad` The EMA score (Exponential Moving Average) reflects a participant's performance over time for a given topic, balancing recent and past achievements, and determines whether the participant stays in the **active set** (eligible for [rewards](https://docs.allora.network/learn/consensus-and-rewards#worker-rewards)) or remains in the **passive set**. Active participants have their EMA score updated based on their current performance; participants who do not contribute during a given [epoch](https://docs.allora.network/learn/key-terms#epochs) receive an adjusted score using a "dummy" value, which determines whether they can re-enter the active set in future epochs. Read about the v0.3.0 release on [Merit-Based Sortitioning](https://docs.allora.network/reference/release-notes#v030) for a deeper dive on what makes up the active and passive sets. The commands below use the testnet RPC endpoint; swap in the mainnet endpoint from [networks](https://docs.allora.network/reference/networks) as needed. #### Worker EMA scores Query the EMA score for a specific worker (identified by its `allo...` address): ```bash allorad q emissions inferer-score-ema [topic_id] [worker_address] --node https://allora-rpc.testnet.allora.network/ ``` Query the lowest EMA score among workers in the topic's active set: ```bash allorad q emissions current-lowest-inferer-score [topic_id] --node https://allora-rpc.testnet.allora.network/ ``` #### Reputer EMA scores The same pair of queries exists for [reputers](https://docs.allora.network/build/reputer/build-a-reputer): ```bash allorad q emissions reputer-score-ema [topic_id] [reputer_address] --node https://allora-rpc.testnet.allora.network/ allorad q emissions current-lowest-reputer-score [topic_id] --node https://allora-rpc.testnet.allora.network/ ``` To determine whether a participant is in the active set and eligible for rewards, compare its EMA score against the lowest EMA score in the active set for the same topic: if the participant's score is higher, it is in the active set. For the full catalog of worker-related chain queries — registration checks, per-block inference scores, latest submitted inference, and network regrets — see [How to Query Worker Data using `allorad`](https://docs.allora.network/build/worker/query-worker-data). ## Verify - Your worker's log shows `✅ Successfully submitted` lines, and the transaction hashes resolve on the [explorer](https://testnet.explorer.allora.network). - The web dashboard at [http://localhost:8787](http://localhost:8787) lists your worker with a `running` status and a populating submission timeline. - `allorad q emissions inferer-score-ema --node https://allora-rpc.testnet.allora.network/` returns a score, and comparing it with `current-lowest-inferer-score` tells you whether you are in the active set. ## Troubleshoot - **Dashboard or `workerctl` shows no workers** — they only track workers deployed through the Builder Kit's `WorkerManager`, and read `worker_state.db` from the current directory. Run them from the directory you deployed in, or pass `--db-path`. Workers started by hand (e.g. `python worker.py`, Docker) are monitored via their logs, the explorer, and `allorad` instead. - **`401 Unauthorized` from the dashboard** — you exposed it beyond localhost, so requests need the auth token printed to stderr at startup: append `?token=...` to the URL. - **EMA query returns no score** — the worker has not been scored yet. Scores appear only after its submissions are included in completed epochs; confirm submissions on the explorer first. - **`allorad: command not found`** — install the CLI: [Allora CLI](https://docs.allora.network/get-started/cli). - **Dashboard `sync_ok=false` or zero on-chain data** — the on-chain sync (every 5 seconds) may be failing; check network access to the RPC endpoint, and the `--network` flag matches where the worker is deployed (`testnet` by default). ## Next - All worker chain queries: [query worker data using `allorad`](https://docs.allora.network/build/worker/query-worker-data) - Understand how scores drive rewards: [worker rewards](https://docs.allora.network/learn/consensus-and-rewards#worker-rewards) - Build or reconfigure your worker: [build a worker with the Python SDK](https://docs.allora.network/build/worker/sdk-py) - Run it unattended: [deploy a worker with Docker](https://docs.allora.network/build/worker/containerize) --- # How to Query Worker Data using allorad Source: https://docs.allora.network/build/worker/query-worker-data Commands for pulling information about workers via allorad. Below is a list of commands to understand how to pull information about workers via [`allorad`](https://docs.allora.network/get-started/cli#installing-allorad): ## Prerequisites - [`allorad` CLI](https://docs.allora.network/get-started/cli) - A basic understanding of the Allora Network ## Query Functions These functions read from the appchain only and do not write. Add the **Command** value into your query to retrieve the expected data. ```bash allorad q emissions [Command] --node ``` ## Check if Worker is Registered in a Topic - **RPC Method:** `IsWorkerRegisteredInTopicId` - **Command:** `is-worker-registered [topic_id] [address]` - **Description:** Checks whether a worker is registered in a specific topic. It returns `true` if the worker is registered in the given topic, and `false` otherwise. - **Positional Arguments:** - `topic_id`: The identifier of the topic where you want to check the worker’s registration status. - `address`: The address of the worker you want to check. ### Use Case: **Why use it?** - This command is essential if you want to verify whether a worker is properly registered in a specific topic before submitting inferences or participating in a topic's operations. **Example Scenario:** - Before deploying a worker to submit inferences on a particular topic, you can confirm that the worker is registered to that topic to ensure proper functionality and avoid errors. --- ## Get Worker Inferences Scores at Block - **RPC Method:** `GetWorkerInferenceScoresAtBlock` - **Command:** `inference-scores [topic_id] [block_height]` - **Description:** Return scores for a worker at a block height. - Scores determine how [worker rewards](https://docs.allora.network/learn/consensus-and-rewards#worker-rewards) are paid out. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Use Case **Why use it?** - You may want to verify if a worker has received a high score at a specific block, particularly if you're troubleshooting worker rewards or performance discrepancies. **Example Scenario:** - If you believe your worker's reward for a particular topic is inaccurate, use this command to view how it was scored at a specific block. --- ## Get Latest Worker Inference By Topic ID - **RPC Method:** `GetWorkerLatestInputInferenceByTopicId` - **Command:** `latest-input-inference [topic_id] [worker_address]` - **Description:** Gets the latest inference submitted by a given worker for a topic. Since v0.17.0 this returns an `InputInference` — the worker's submitted payload, including its labeled `values`. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned - `worker_address` Given worker to query on > In v0.17.0 this query was renamed from `GetWorkerLatestInferenceByTopicId` (`worker-latest-inference`) to `GetWorkerLatestInputInferenceByTopicId` (`latest-input-inference`). ### Use Case **Why use it?** - This command is useful if you want to check whether a worker is actively submitting inferences for a topic and how recent those inferences are. **Example Scenario:** - A worker has missed rewards, and you want to verify if their latest inference was successfully submitted on time for a given topic. --- ## Get Worker Node Info - **RPC Method:** `GetWorkerNodeInfo` - **Command:** `worker-info [address]` - **Description:** Get node info for a specified worker node. - Returns the **owner address** of the worker node. - Returns the **worker node address** being queried. - **Positional Arguments:** - `address` The address of the worker node whose information will be retrieved. ### Use Case **Why use it?** - This command is helpful for checking the current status of a worker node, especially if you are managing multiple nodes and want to verify the ownership or troubleshoot node configuration. **Example Scenario:** - You want to ensure the node you’ve set up is operating under the correct owner and is correctly registered on the network. --- ## Get Naive Inferer Network Regret - **RPC Method:** `GetNaiveInfererNetworkRegret` - **Command:** `naive-inferer-network-regret [topic_id] [inferer]` - **Description:** Returns the network regret associated with including an inferer's naive inference in a batch for a given topic. If no specific regret is calculated, the command defaults to the topic's `InitialRegret` value. - **Positional Arguments:** - `topic_id`: The identifier of the topic for which the regret will be calculated. - `inferer`: The address of the inferer whose naive inference is being evaluated. ### Use Case: **Why use it?** - Use this command to assess the [regret](https://docs.allora.network/learn/key-terms#regrets) associated with incorporating an inferer’s naive inference into a batch. Useful for analyzing how poorly an inference may perform within the context of the network’s aggregate inference for a topic. **Example Scenario:** - If you want to understand how an inferer's baseline performance impacts the network outcome, this command helps quantify that penalty. --- ## Get One-Out Inferer-Inferer Network Regret - **RPC Method:** `GetOneOutInfererInfererNetworkRegret` - **Command:** `one-out-inferer-inferer-network-regret [topic_id] [one_out_inferer] [inferer]` - **Description:** Returns the network regret when the implied outcome of the `one_out_inferer` is included in a batch alongside the `inferer`. If no specific regret value exists, it defaults to the topic’s `InitialRegret`. - **Positional Arguments:** - `topic_id`: The identifier of the topic for which the regret will be calculated. - `one_out_inferer`: The address of the inferer whose implied inference is being evaluated. - `inferer`: The address of the inferer to compare against. ### Use Case: **Why use it?** - This command is useful when comparing how two inferers impact the network when their inferences are processed together. It helps identify the potential penalty on network performance when adding a specific inferer to a batch. **Example Scenario:** - You might want to compare the impact of two inferers to see how their joint performance influences the overall network regret. This is particularly useful for optimizing inference strategies. --- # Build and Deploy a Forecaster Source: https://docs.allora.network/build/forecaster/build-and-deploy-a-forecaster What forecasters do on Allora, and how to submit forecasted losses to a topic with the Python SDK's AlloraWorker.forecaster. A **forecaster** is a worker that predicts how accurate other workers' inferences will be, instead of (or in addition to) answering the topic's question itself. For each inferer, it submits a **forecasted loss** — an estimate of the error that inferer's inference will show against the eventual ground truth. The network turns forecasted losses into [regrets and weights](https://docs.allora.network/learn/inference-synthesis#forecast) and combines them into [forecast-implied inferences](https://docs.allora.network/learn/inference-synthesis#forecast-implied-inferences), making the network inference [context-aware](https://docs.allora.network/learn/inference-synthesis#context-awareness) — better than any individual model's output. [Forecast and Synthesis](https://docs.allora.network/learn/inference-synthesis) explains the mechanism end to end. The forecaster role has the same first-class tooling as the inferer: [`AlloraWorker.forecaster(...)`](https://docs.allora.network/consume/sdk-py) (`allora_sdk` 1.3.0) handles wallet creation, testnet faucet funding, registration, submission windows, and transaction submission — you supply one Python function that returns your forecasted losses. ## Goal Register a worker on an Allora testnet topic and submit a forecast — predicted losses for the topic's active inferers — with the Python SDK's ([`allora_sdk`](https://pypi.org/project/allora-sdk/)) `AlloraWorker.forecaster`. ## Prerequisites - Python 3.10–3.13 - An Allora API key — get one for free at [developer.allora.network](https://developer.allora.network). On testnet, the worker uses it to automatically request ALLO gas from the faucet. - A topic with active inferers to forecast on. The example uses [Allora's testnet sandbox topic (ID 69)](https://testnet.explorer.allora.network/topics/69); browse [existing topics](https://docs.allora.network/build/forge/topics) for others. If you already ran an [inference worker](https://docs.allora.network/build/worker/sdk-py) in the same directory, the forecaster reuses the identity saved in its `.allora_key` file; otherwise it creates one on first run. ## Steps ### 1. Install the SDK ```bash pip install allora_sdk ``` ### 2. Understand the forecast function `AlloraWorker.forecaster(...)` takes a `run` function that returns one predicted loss per inferer, as a dict keyed by the inferer's `allo...` address: ```python {"allo1...": 0.05} # your predicted loss for this inferer, this epoch ``` The SDK converts the dict into the chain's `forecast_elements` format and submits it as a worker payload — the same `insert_worker_payload` transaction inferers send, with the forecast in place of an inference. A worker payload can also carry both at once — a combination the network explicitly supports ([some workers do both](https://docs.allora.network/learn/inference-synthesis#losses)) — by calling the lower-level `client.emissions.tx.insert_worker_payload()` with `inference_value` and `forecast_elements` together. ### 3. Write the forecaster Save this as `forecaster.py`, replacing the model logic in `forecast_losses` with your own. The function receives a [`RunContext`](https://docs.allora.network/build/worker/sdk-py) — the submission window's `nonce`, the `topic_id`, and an RPC `client` — and uses the client to look up the topic's current inferers: ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext from allora_sdk.rpc_client.protos.emissions.v10 import GetLatestNetworkInferencesRequest TOPIC_ID = 69 async def forecast_losses(ctx: RunContext) -> dict[str, float]: # Find the inferers whose accuracy you are forecasting latest = await ctx.client.emissions.query.get_latest_network_inferences( GetLatestNetworkInferencesRequest(topic_id=ctx.topic_id) ) if latest.network_inferences is None or not latest.network_inferences.inferer_values: raise RuntimeError(f"Topic {ctx.topic_id} has no network inferences yet -- nothing to forecast") inferers = [v.worker for v in latest.network_inferences.inferer_values] # Your ML model goes here: for each inferer, predict the loss of the # inference it submits this epoch. return {address: 0.05 for address in inferers} async def main(): worker = AlloraWorker.forecaster( run=forecast_losses, topic_id=TOPIC_ID, network=AlloraNetworkConfig.testnet(), api_key=os.environ["ALLORA_API_KEY"], ) async for result in worker.run(): if isinstance(result, Exception): print(f"Forecast worker error: {result}") else: print(f"Forecast for {len(result.submission)} inferers submitted in transaction {result.tx_result.txhash}") asyncio.run(main()) ``` ### 4. Run it ```bash export ALLORA_API_KEY="" python forecaster.py ``` On the first run, the worker walks you through onboarding exactly like the [inference worker](https://docs.allora.network/build/worker/sdk-py): it asks for a wallet mnemonic (press **Enter** to generate one; it is saved to `.allora_key` and reused), requests testnet ALLO from the faucet using your API key, and registers your address on the topic. It then listens for the topic's submission windows and calls `forecast_losses` each time one opens. ## Verify - Each time a submission window opens, the terminal prints `Forecast for N inferers submitted in transaction `, and the log shows `✅ Successfully submitted: topic=69 nonce=...`. - Read the forecast back from the chain — run this separately, with the nonce (block height) from your submission log: ```python import asyncio from allora_sdk import AlloraRPCClient from allora_sdk.rpc_client.protos.emissions.v10 import GetForecastsAtBlockRequest async def main(): client = AlloraRPCClient.testnet() forecasts = await client.emissions.query.get_forecasts_at_block( GetForecastsAtBlockRequest(topic_id=69, block_height=10353455) # your nonce here ) if forecasts.forecasts is not None: print([f.forecaster for f in forecasts.forecasts.forecasts]) asyncio.run(main()) ``` Your `allo...` address should appear in the printed list of forecasters. - Open [testnet.explorer.allora.network/topics/69](https://testnet.explorer.allora.network/topics/69) and look for your address among the topic's workers. ## Troubleshoot - **gRPC `StatusCode.UNIMPLEMENTED` with `unknown service emissions.vN.QueryService`** — the network has been upgraded to a newer protobuf revision than the one bundled with your installed SDK release. Upgrade with `pip install --upgrade allora_sdk`; if the newest release still fails, the deployed network is ahead of the latest SDK release — check the [SDK issue tracker](https://github.com/allora-network/allora-sdk-py/issues). - **`The wallet ... is not whitelisted on topic ...`** — the topic restricts who may submit worker payloads and the worker stops. Contact the topic creator to get your address whitelisted, or use the [sandbox topic (ID 69)](https://testnet.explorer.allora.network/topics/69). - **Rejections with code 68, 75, or 78** — you already submitted a worker payload for this nonce. The worker recognizes these, logs a warning, and waits for the next submission window; each address submits at most one payload per epoch. - **`Topic ... has no network inferences yet`** — forecasting needs inferences to forecast against. Pick a topic with active inferers ([existing topics](https://docs.allora.network/build/forge/topics)), or wait until the topic completes an epoch with inference submissions. - **`Too many faucet requests`** — the testnet faucet is rate-limited. Send ALLO to your worker's address from another wallet, or request funds manually at [faucet.testnet.allora.network](https://faucet.testnet.allora.network). ## Next - How forecasts become weights and forecast-implied inferences: [Forecast](https://docs.allora.network/learn/inference-synthesis#forecast) and [Synthesis](https://docs.allora.network/learn/inference-synthesis#synthesis) - Submit plain inferences with the high-level worker: [Allora Python SDK](https://docs.allora.network/consume/sdk-py) or [build a worker with the Python SDK](https://docs.allora.network/build/worker/sdk-py) - Find topics with active inferers: [existing topics](https://docs.allora.network/build/forge/topics) - Inspect your worker's on-chain data: [query worker data using allorad](https://docs.allora.network/build/worker/query-worker-data) --- # Reputers Source: https://docs.allora.network/build/reputer Reputers ensure the accuracy and reliability of worker inferences and the overall integrity of topics. Reputers ensure the accuracy and reliability of worker inferences and the overall integrity of topics. ## What do Reputers do? ### Source Ground Truth Reputers source the ground truth as specified by the [topic metadata](https://docs.allora.network/operate/topics/create#creating-your-first-topic). For example, they might retrieve the actual price of ETH at a specific moment in time. This ground truth is essential for evaluating the accuracy of inferences made by workers. ### Calculate Loss Reputers calculate the loss of worker inferences and forecast-implied inferences relative to the ground truth. For instance, if a topic's [loss function](https://docs.allora.network/operate/topics/create) is an L1-norm, reputers apply this norm to each worker's inference and the actual price of ETH in 10 days. They then respond with a [`ValueBundle` of losses](https://github.com/allora-network/allora-chain/blob/1d56c50c8d0f43446d770cf387dbd43bb3613e8c/x/emissions/proto/emissions/v1/reputer.proto#L28), detailing the calculated losses for each inference. ### Secure Topics with Stake Reputers secure topics with their [stake](https://docs.allora.network/build/reputer/set-and-adjust-stake). The more a reputer stakes in a topic, the greater their influence on the consensus of losses. Additionally, reputers can be [delegated to](https://docs.allora.network/reference/allorad#delegate-stake-to-a-reputer-for-a-topic), increasing their ability to secure the topic further. This delegated stake enhances the extent to which reputers secure the topic as opposed to the broader chain security. ### Receive Rewards Reputers [receive rewards](https://docs.allora.network/learn/consensus-and-rewards#reputer-rewards) based on how close their reported losses are to the consensus. A stake-weighted average of each reported loss is taken among reputers per topic per epoch. The closer a reputer's values are to this average, the more they are rewarded. This system incentivizes reputers to provide accurate and reliable loss calculations, contributing to the network's overall integrity and reliability. --- # Build a Reputer Source: https://docs.allora.network/build/reputer/build-a-reputer Configure and run an Allora reputer node that serves ground truth and computes losses, stake ALLO on a topic, and verify your reputer's status. [Reputers](https://docs.allora.network/learn/consensus-and-rewards#reputer-rewards) are the Allora Network's source of truth. Each epoch, a reputer fetches the network's inferences for its topic, compares them against ground truth obtained from its own data sources, computes losses using the topic's loss method, and submits the resulting loss bundle on-chain. Reputers must [stake ALLO](https://docs.allora.network/build/reputer/set-and-adjust-stake), and rewards depend on accuracy relative to reputer consensus and on stake. This page runs a reputer on the [`allora-offchain-node`](https://github.com/allora-network/allora-offchain-node), which handles registration, staking, submission windows, and transaction retries. You supply two HTTP services: one that returns the ground truth and one that computes the loss. The [Python SDK](https://docs.allora.network/consume/sdk-py) can run the same role in-process — see the callout in step 5. ## Goal Run a reputer for a topic with `allora-offchain-node`: configure the node, point it at your ground-truth and loss-function services, put stake behind it, and verify your registration, stake, and EMA score. ## Prerequisites - Git and Docker (with Docker Compose) - A wallet mnemonic — or let the node create keys for you on first run - ALLO on the target network to register and stake — on testnet, request funds from the [Allora Testnet Faucet](https://faucet.testnet.allora.network/) - The ID of the [topic](https://docs.allora.network/build/forge/topics) you want to provide ground truth for - The [`allorad` CLI](https://docs.allora.network/get-started/cli) for verification commands ## Steps ### 1. Clone the node and create your config ```bash git clone https://github.com/allora-network/allora-offchain-node.git cd allora-offchain-node cp config.example.json config.json ``` ### 2. Configure your wallet In `config.json`, fill in the `wallet` section: - `addressKeyName`: a wallet name of your choice — required; the node's `init.config` script exits with an error if it is empty. - `addressRestoreMnemonic`: the mnemonic of your existing [wallet](https://docs.allora.network/get-started/setup-wallet), or leave it empty to have a new key created automatically under `addressKeyName` — the generated address is written to `./data/env_file`, and you will need to fund it before the node can register and stake. - `nodeRpcs` and `nodegRpcs`: lists of RPC and gRPC endpoints for the target network (the example config points at testnet). See [Networks](https://docs.allora.network/reference/networks) for endpoints. ### 3. Configure the reputer The `reputer` section of `config.json` is an array with one entry per topic. This is the shape from `config.example.json`: ```json "reputer": [ { "topicId": 1, "groundTruthEntrypointName": "apiAdapter", "lossFunctionEntrypointName": "apiAdapter", "minStake": 100000000, "groundTruthParameters": { "GroundTruthEndpoint": "http://localhost:8888/gt/{Token}/{BlockHeight}", "LabeledGroundTruthEndpoint": "http://localhost:8888/lgt/{Token}/{BlockHeight}", "Token": "ETHUSD" }, "lossFunctionParameters": { "LossFunctionService": "http://localhost:5000", "LabeledLossFunctionService": "http://localhost:5000/labeled", "LossMethodOptions": { "loss_method": "sqe" } } } ] ``` - `topicId`: the topic your reputer provides ground truth for. - `groundTruthEntrypointName` / `lossFunctionEntrypointName`: which adapter the node uses to reach your services. `apiAdapter` calls them over HTTP (see the [`adapter` directory](https://github.com/allora-network/allora-offchain-node/tree/dev/adapter)). - `minStake`: the stake (in `uallo`) the node ensures is placed for your reputer on the topic. If your existing stake is below this amount, the node pulls the difference from your wallet. Set it at or above the chain's [`required_minimum_stake`](https://docs.allora.network/reference/params/chain#required_minimum_stake) parameter — below that minimum, your contributions to reputation scoring are ignored and you earn no rewards. - `groundTruthParameters`: `GroundTruthEndpoint` is the URL of your ground-truth service; it supports the `{Token}`, `{TopicId}`, and `{BlockHeight}` template variables, where extra variables such as `Token` are defined alongside it in the same block. - `lossFunctionParameters`: `LossFunctionService` is the base URL of your loss service. `LossMethodOptions.loss_method` must be the loss method the topic declares in its on-chain configuration; any additional options (for example `"delta": "1.0"` for a Huber loss) are passed through to your loss service unchanged. Whether the scalar or the `Labeled*` endpoints are used is decided by the topic's on-chain output arity: `SINGLE` topics use `GroundTruthEndpoint` and `LossFunctionService`, while multi-label (`MULTI`) topics — classification topics, for example — use `LabeledGroundTruthEndpoint` and `LabeledLossFunctionService`. To run a reputer only, configure just the `reputer` array — the `worker` section of the example config is for the node's legacy inference-worker mode (see [Migrate from the Offchain Node](https://docs.allora.network/build/migrate-from-offchain-node)) and can be removed. ### 4. Serve ground truth and losses over HTTP Your two services implement a small contract, documented in the [API adapter README](https://github.com/allora-network/allora-offchain-node/blob/dev/adapter/api/apiadapter/README.md): - The **ground-truth endpoint** returns the true value for the requested block height as plain text (a single scalar for `SINGLE` topics). For example, a reputer on an ETH price topic would return the actual ETH price at the epoch's block height. - The **loss-function service** exposes two endpoints, created by appending to the configured base URL: `/calculate`, which receives the ground truth (`y_true`), a predicted value (`y_pred`), and your `LossMethodOptions`, and returns the loss; and `/is_never_negative`, which tells the node whether the loss method can produce negative values. The node calls your ground-truth service once per epoch and your loss service for every value in the epoch's inference bundle — the combined network inference, each worker's individual inference, and the one-out variants the network uses for scoring. ### 5. Fund, initialize, and start the node Load your config into the environment: ```bash chmod +x init.config ./init.config ``` If you let the node create keys in step 2, fund the address recorded in `./data/env_file` now (on testnet, use the [faucet](https://faucet.testnet.allora.network/)). Re-run `./init.config` after any change to `config.json`. Then start everything: ```bash docker compose up --build ``` On startup the node registers your reputer on each configured topic and tops your stake up to `minStake`. It then submits a loss bundle every epoch — reputer submission windows are one full topic epoch long. **Also in the Python SDK.** As of `allora_sdk` 1.3.0 (the latest release on PyPI), `AlloraWorker.reputer(...)` runs the reputer role in-process, with no offchain node or HTTP services: it takes a reputer function — built from a ground-truth function and a loss function via the `make_reputer_function(get_ground_truth, loss_fn)` helper — and automates the fetch–compute–submit cycle, with an optional self-stake top-up to `min_stake_uallo` after each submission. The SDK ships default implementations of the loss methods used on the network: squared error (`sqe`/`mse`), absolute error (`abse`/`mae`), Huber (`huber`), log-cosh (`logcosh`), binary cross-entropy (`bce`), Poisson (`poisson`), and the z-transformed variants `ztae` and `zptae` (parameterized via `make_ztae_loss`/`make_zptae_loss` with the standard deviation of historical values). ## Verify Check your reputer's registration and stake with `allorad`, as described in [How to Query Reputer Data](https://docs.allora.network/build/reputer/query-reputer-data): ```bash allorad q emissions is-reputer-registered [topic_id] [address] --node https://allora-rpc.testnet.allora.network/ allorad q emissions stake-in-topic-reputer [address] [topic_id] --node https://allora-rpc.testnet.allora.network/ ``` `is-reputer-registered` should return `true`, and your stake should be at least the `minStake` you configured. Once the node is submitting loss bundles, track your EMA score and compare it against the lowest score in the topic's active set to confirm you are eligible for rewards — see [query EMA scores with `allorad`](https://docs.allora.network/build/worker/monitoring#5-query-ema-scores-with-allorad). ## Troubleshoot - **Registration or staking fails with an insufficient-funds error** — the wallet must hold ALLO on the network you target. On testnet, request funds from the [faucet](https://faucet.testnet.allora.network/), then restart the node. - **The node fails at startup with a missing-endpoint error** — the topic's output arity requires an endpoint you have not configured. `SINGLE` topics need `GroundTruthEndpoint` and `LossFunctionService`; `MULTI` topics need `LabeledGroundTruthEndpoint` and `LabeledLossFunctionService`. - **Submissions are rejected for a whitelisted topic** — the node checks whether your address is whitelisted before submitting. If the topic enforces a reputer whitelist, ask the topic creator to whitelist your address. - **Registered and submitting, but no rewards** — verify your stake meets the chain's [`required_minimum_stake`](https://docs.allora.network/reference/params/chain#required_minimum_stake); below it, your contributions are ignored. Also compare your EMA score against the topic's active set as shown in [query EMA scores with `allorad`](https://docs.allora.network/build/worker/monitoring#5-query-ema-scores-with-allorad). - **Chain version errors** — the current node targets the v10 Allora chain emissions API and is not backward-compatible with v9 chains. Run the latest node release against a v10 network. ## Next - Manage your stake: [Set and Adjust Stake](https://docs.allora.network/build/reputer/set-and-adjust-stake) - Query reputer data with `allorad`: [How to Query Reputer Data](https://docs.allora.network/build/reputer/query-reputer-data) - Understand scoring and the active set: [query EMA scores with `allorad`](https://docs.allora.network/build/worker/monitoring#5-query-ema-scores-with-allorad) - Running an inference worker too? [Migrate a worker from the offchain node](https://docs.allora.network/build/migrate-from-offchain-node) - Explore the Python SDK: [Allora Python SDK](https://docs.allora.network/consume/sdk-py) --- # Deploy a Reputer Node using Docker Source: https://docs.allora.network/build/reputer/deploy-docker Deploying a reputer in the Allora network involves configuring the config.example.json file to ensure your reputer can interact with the network and provide accurate truth data. Deploying a reputer in the Allora network involves configuring the `config.example.json` file to ensure your reputer can interact with the network and provide accurate truth data. To build this setup, please follow these steps: ## Prerequisites Ensure you have the following installed on your machine: - Git - Go (version 1.16 or later) - Docker ## Clone the `allora-offchain-node` Repository Download the `allora-offchain-node` git repo: ```bash git clone https://github.com/allora-network/allora-offchain-node cd allora-offchain-node ``` ## Configure Your Environment 1. Copy `config.example.json` and name the copy `config.json`. 2. Open `config.json` and **update** the necessary fields inside the `wallet` sub-object and `worker` config with your specific values: ### `wallet` Sub-object 1. `nodeRpc`: The [RPC URL](https://docs.allora.network/get-started/setup-wallet#rpc-url-and-chain-id) for the corresponding network the node will be deployed on 2. `addressKeyName`: The name you gave your wallet key when [setting up your wallet](https://docs.allora.network/get-started/setup-wallet) 3. `addressRestoreMnemonic`: The mnemonic that was outputted when setting up a new key ### `reputer` Config 1. `topicId`: The specific topic ID you created the reputer for. 2. `SourceOfTruthEndpoint`: The endpoint exposed by your source of truth server to provide the truth data to the network. 3. `Token`: The token for the specific topic you are verifying truth data for. This token should be included in the source of truth endpoint for retrieval. - The `Token` variable is specific to the endpoint you expose in your `main.py` file. It is **not** related to any blockchain parameter and is only locally specific. 4. `minStake`: The minimum stake required to participate as a reputer. This stake will be deducted from the reputer's wallet balance. When placing your minimum stake, the system will verify the amount of funds you have already staked in the topic. If your staked amount is insufficient, it will automatically pull the necessary funds from your wallet to meet the required minimum. The `reputer` config is an array of sub-objects, each representing a different topic ID. This structure allows you to manage multiple topic IDs, each within its own sub-object. To deploy a reputer that provides inferences for multiple topics, you can duplicate the existing sub-object and add it to the `reputer` array. Update the `topicId`, `SourceOfTruthEndpoint`, `minStake` and `Token` fields with the appropriate values for each new topic: ```json "worker": [ { "topicId": 1, "reputerEntrypointName": "api-worker-reputer", "loopSeconds": 30, "minStake": 100000, "parameters": { "SourceOfTruthEndpoint": "http://source:8888/truth/{Token}/{BlockHeight}", "Token": "ethereum" } }, // reputer providing ground truth for topic ID 2 { "topicId": 2, "reputerEntrypointName": "api-worker-reputer", "loopSeconds": 30, "minStake": 100000, "parameters": { "SourceOfTruthEndpoint": "http://source:8888/truth/{Token}/{BlockHeight}", "Token": "ethereum" } } ], ``` ### Worker Config The `config.example.json` file that was copied and edited in the previous steps also contains a JSON object for the node's legacy inference-worker mode (deprecated — see [Migrate from the Offchain Node](https://docs.allora.network/build/migrate-from-offchain-node)). To ignore the worker and only deploy a reputer, delete the worker sub-object from the `config.json` file. ## Create the Truth Server ### Prepare the API Gateway Ensure you have an API gateway or server that can accept API requests to call your model. ### Server Responsibilities - Accept API requests from `main.go`. - Respond with the corresponding inference obtained from the model. ### Truth Relay Below is a sample structure of what your `main.go`, `main.py` and Dockerfile will look like. #### `main.go` `allora-offchain-node` comes preconfigured with an API adapter — see the [`adapter` directory](https://github.com/allora-network/allora-offchain-node/tree/dev/adapter) — whose `main.go` fetches the responses outputted from the Source of Truth Endpoint based on the `SourceOfTruthEndpoint` and `Token` provided in the section above. #### `main.py` `allora-offchain-node` comes preconfigured with a Flask application that uses a `main.py` file to expose the Source of Truth Endpoint. The Flask application serves the request from `main.go`, which is routed to the `get_truth` function using the required arguments (`Token`, `blockHeight`). Before proceeding, ensure that all necessary packages are listed in the `requirements.txt` file. ```python from flask import Flask from model import get_inference # Importing the hypothetical model app = Flask(__name__) @app.route('/truth//', methods=['GET']) def get_truth(token, blockheight): random_float = str(random.uniform(0.0, 100.0)) return random_float if __name__ == '__main__': app.run(host='0.0.0.0') ``` The source of truth in `allora-offchain-node` is barebones and outputs a random number. Replace the body of `get_truth` with logic that fetches real data for your topic — for example, the price of an asset at the requested block height from a market-data API. #### `Dockerfile` A sample Dockerfile has been created in `allora-offchain-node` that can be used to deploy your model on port 8000. ```dockerfile FROM python:3.9-slim RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD ["python", "main.py"] ``` ## Running the Node Now that the node is configured, let's deploy and register it to the network. To run the node, follow these steps: ### Export Variables Execute the following command from the root directory: ```sh chmod +x init.config ./init.config ``` This command will automatically export the necessary variables from the account created. These variables are used by the offchain node and are bundled with your provided `config.json`, then passed to the node as environment variables. If you need to **make changes** to your `config.json` file after you ran the `init.config` command, rerun: ```sh chmod +x init.config ./init.config ``` before proceeding. ### Request from Faucet Copy your Allora address and request some tokens from the [Allora Testnet Faucet](https://faucet.testnet.allora.network/) to register your worker in the next step successfully. ### Deploy the Node ``` docker compose up --build ``` Both the offchain node and the source services will be started. They will communicate through endpoints attached to the internal DNS. A **successful** response from your Reputer should display: ```bash {"level":"debug","msg":"Send Reputer Data to chain","txHash":"","time":"","message":"Success"} ``` Congratulations! You've successfully deployed and registered your node on Allora. ## Learn More For a guide based on the current `allora-offchain-node` configuration format — including the ground-truth and loss-function service contract, staking, and verification — see [Build a Reputer](https://docs.allora.network/build/reputer/build-a-reputer). --- # Set and Adjust Stake Source: https://docs.allora.network/build/reputer/set-and-adjust-stake We define stake, motivate its use, and demonstrate how it can be adjusted. > We define stake, motivate its use, and demonstrate how it can be adjusted ## How Stake works for Reputers [Stake](https://docs.allora.network/learn/key-terms#stake) is used to signal confidence. A reputer earns more rewards based on their accuracy comparative to consensus (the other reputers providing data for a topic) and stake. Stake also protects Allora from malicious behavior, such as sybil attacks. We require all types of nodes to register on the chain before they can earn any rewards. Registering requires staking at least a minimum amount of ALLO. As a result, creating an army of malicious nodes would quickly become prohibitively expensive. ## Prerequisites - [`allorad` CLI](https://docs.allora.network/get-started/cli) ## Tx Functions These functions read from the appchain only and do not write. Add the **Command** value into your query to retrieve the expected data. ```bash allorad tx emissions [Command] --node ``` ## Add Stake to Self - **RPC Method:** `AddStake` - **Command:** `add-stake [sender] [topic_id] [amount]` - **Description:** Adds stake to the sender for a specific topic. - **Positional Arguments:** - `sender`: The address of the sender adding stake. - `topic_id`: The identifier of the topic. - `amount`: The amount of stake to be added. ### Use Case: **Why use it?** - This command is used when a reputer or worker wants to increase their stake in a specific topic, increasing their influence or authority. **Example Scenario:** - As a reputer, you want to increase your stake in a specific topic to gain more influence and improve your reputation scores. --- ## Remove Stake from Self - **RPC Method:** `RemoveStake` - **Command:** `remove-stake [sender] [topic_id] [amount]` - **Description:** Removes stake from the sender (a reputer) in a specific topic. - **Positional Arguments:** - `sender`: The address of the sender removing stake (reputer). - `topic_id`: The identifier of the topic. - `amount`: The amount of stake to be removed. ### Use Case: **Why use it?** - This command is used by reputers to reduce their stake in a topic, either for liquidity purposes or when their role in the topic has changed. **Example Scenario:** - A reputer wants to reduce their stake in a topic after completing their contributions and being satisfied with the rewards. --- ## Cancel Pending Stake Removal (Reputer) - **RPC Method:** `CancelRemoveStake` - **Command:** `cancel-remove-stake [sender] [topic_id]` - **Description:** Cancels the removal of stake that is pending for the sender (a reputer) in a topic. - **Positional Arguments:** - `sender`: The address of the sender canceling the stake removal (reputer). - `topic_id`: The identifier of the topic. ### Use Case: **Why use it?** - This command allows reputers to cancel a stake removal request if they change their mind and wish to keep their stake in the topic. **Example Scenario:** - A reputer wants to cancel their stake removal request because they decide to maintain their position in the topic for an additional epoch. --- ## Delegate Stake to a Reputer - **RPC Method:** `DelegateStake` - **Command:** `delegate-stake [sender] [topic_id] [reputer] [amount]` - **Description:** Delegates stake from the sender to a specific reputer for a topic. - **Positional Arguments:** - `sender`: The address of the sender (delegator). - `topic_id`: The identifier of the topic. - `reputer`: The address of the reputer receiving the delegated stake. - `amount`: The amount of stake to be delegated. ### Use Case: **Why use it?** - This command is used by delegators to delegate their stake to a reputer, giving the reputer more authority and influence within a specific topic. **Example Scenario:** - As a delegator, you want to support a reputer you trust by delegating your tokens to them for a particular topic. --- ## Remove Delegated Stake from a Reputer - **RPC Method:** `RemoveDelegateStake` - **Command:** `remove-delegate-stake [sender] [topic_id] [reputer] [amount]` - **Description:** Removes delegated stake from a reputer for a topic. - **Positional Arguments:** - `sender`: The address of the sender (delegator). - `topic_id`: The identifier of the topic. - `reputer`: The address of the reputer whose delegated stake is being removed. - `amount`: The amount of stake to be removed. ### Use Case: **Why use it?** - This command is used when a delegator wants to withdraw or reduce the stake they have delegated to a reputer in a topic. **Example Scenario:** - A delegator wants to reduce their stake delegated to a reputer after reassessing the reputer's performance in a topic. --- ## Cancel Pending Delegated Stake Removal - **RPC Method:** `CancelRemoveDelegateStake` - **Command:** `cancel-remove-delegate-stake [sender] [topic_id] [reputer]` - **Description:** Cancels the removal of delegated stake for a delegator staking on a reputer in a topic. - **Positional Arguments:** - `sender`: The address of the sender (delegator). - `topic_id`: The identifier of the topic. - `reputer`: The address of the reputer whose delegated stake removal is being canceled. ### Use Case: **Why use it?** - This command allows delegators to cancel a delegated stake removal request if they change their mind and want to keep their stake with the reputer. **Example Scenario:** - A delegator decides to cancel their pending stake removal and continue supporting the reputer in the topic. --- ## Claim Rewards for Delegated Stake - **RPC Method:** `RewardDelegateStake` - **Command:** `reward-delegate-stake [sender] [topic_id] [reputer]` - **Description:** Claims the rewards for a delegator who has delegated stake to a reputer in a specific topic. - **Positional Arguments:** - `sender`: The address of the sender (delegator). - `topic_id`: The identifier of the topic. - `reputer`: The address of the reputer to whom the stake was delegated. ### Use Case: **Why use it?** - This command is used by delegators to claim their rewards based on the performance of the reputer they delegated stake to. **Example Scenario:** - A delegator wants to claim their rewards for a topic after their reputer has successfully contributed to the topic's outcomes. --- # How to Query Reputer Data using allorad Source: https://docs.allora.network/build/reputer/query-reputer-data Commands for pulling information about reputers via allorad. Below is a list of commands to understand how to pull information about reputers via [`allorad`](https://docs.allora.network/get-started/cli#installing-allorad): ## Prerequisites - [`allorad` CLI](https://docs.allora.network/get-started/cli) - A basic understanding of the Allora Network ## Query Functions These functions read from the appchain only and do not write. Add the **Command** value into your query to retrieve the expected data. ```bash allorad q emissions [Command] --node ``` ## Check if Reputer is Registered in a Topic - **RPC Method:** `IsReputerRegisteredInTopicId` - **Command:** `is-reputer-registered [topic_id] [address]` - **Description:** Checks whether a reputer is registered in a specific topic. Returns `true` if the reputer is registered in the given topic, and `false` otherwise. - **Positional Arguments:** - `topic_id`: The identifier of the topic where you want to check the reputer’s registration status. - `address`: The address of the reputer you want to check. ### Use Case: **Why use it?** - This command is essential for verifying whether a reputer is properly registered in a specific topic before submitting reputation-related data or participating in topic-related activities. **Example Scenario:** - Before a reputer attempts to evaluate workers or participate in consensus, you can confirm if they are registered to the relevant topic, ensuring their eligibility for participation. ## Check Reputer Stake in a Topic - **RPC Method:** `GetReputerStakeInTopic` - **Command:** `stake-in-topic-reputer [address] [topic_id]` - **Description:** Retrieves the stake a reputer has in a specific topic, including any stake that has been delegated to them. - **Positional Arguments:** - `address`: The address of the reputer whose stake is being queried. - `topic_id`: The identifier of the topic. ### Use Case: **Why use it?** - This command is essential for understanding the total stake a reputer holds in a specific topic, including delegated stake, which is important for determining their influence. **Example Scenario:** - Before delegating more stake, you may want to check how much stake a reputer already has in a particular topic. --- ## Get Total Delegate Stake in a Reputer for a Topic - **RPC Method:** `GetDelegateStakeInTopicInReputer` - **Command:** `stake-total-delegated-in-topic-reputer [reputer_address] [topic_id]` - **Description:** Retrieves the total amount of stake delegated to a reputer for a specific topic. - **Positional Arguments:** - `reputer_address`: The address of the reputer. - `topic_id`: The identifier of the topic. ### Use Case: **Why use it?** - This command provides insight into how much stake has been delegated to a reputer for a given topic, which can impact their role in network consensus. **Example Scenario:** - As a delegator, you may want to see how much stake has already been delegated to a reputer before deciding to contribute more. --- ## Get Stake Delegated to a Reputer - **RPC Method:** `GetDelegateStakePlacement` - **Command:** `delegate-stake-placement [topic_id] [delegator] [target]` - **Description:** Retrieves the amount of tokens delegated to a specific reputer by a given delegator for a topic. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `delegator`: The address of the delegator. - `target`: The address of the target reputer. ### Use Case: **Why use it?** - Use this command to track how much stake a delegator has assigned to a particular reputer in a specific topic. **Example Scenario:** - A delegator can check the exact amount of tokens they have staked on a specific reputer within a topic. --- ## Get Removed Delegated Stake from a Reputer - **RPC Method:** `GetDelegateStakeRemoval` - **Command:** `delegate-stake-removal [block_height] [topic_id] [delegator] [reputer]` - **Description:** Retrieves the current state of a pending delegate stake removal for a delegator in a topic. - **Positional Arguments:** - `block_height`: The block height at which the removal is pending. - `topic_id`: The identifier of the topic. - `delegator`: The address of the delegator. - `reputer`: The address of the target reputer. #### Use Case: **Why use it?** - This command helps track pending removals of delegated stake, ensuring visibility into the process of un-staking tokens from a reputer. **Example Scenario:** - A delegator can check the status of their pending delegate stake removal request. --- ## Get Total Stake Delegated to a Reputer - **RPC Method:** `GetDelegateStakeUponReputer` - **Command:** `delegate-stake-on-reputer [topic_id] [target]` - **Description:** Retrieves the total amount of tokens delegated to a reputer in a specific topic. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `target`: The address of the target reputer. ### Use Case: **Why use it?** - This command provides insight into the total delegated stake a reputer has accumulated in a given topic, which impacts their standing in the network. **Example Scenario:** - You may want to know how much stake has been assigned to a reputer before deciding to interact with them in the topic. --- ## Get Reputer's Latest Score in a Topic - **RPC Method:** `GetReputerScoreEma` - **Command:** `reputer-score-ema [topic_id] [reputer]` - **Description:** Returns the latest Exponential Moving Average (EMA) score for a reputer in a specific topic. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `reputer`: The address of the reputer. ### Use Case: **Why use it?** - This command allows you to track the latest performance score of a reputer, giving insight into their effectiveness within the network. **Example Scenario:** - Before delegating stake, you may want to see how well a reputer is performing in terms of their most recent EMA score. --- ## Get Reputer's Stake Removal Information - **RPC Method:** `GetStakeRemovalForReputerAndTopicId` - **Command:** `stake-removal [reputer] [topic_id]` - **Description:** Retrieves information about a pending stake removal request for a reputer in a specific topic. - **Positional Arguments:** - `reputer`: The address of the reputer. - `topic_id`: The identifier of the topic. ### Use Case: **Why use it?** - Use this command to check the details of any pending stake removal for a reputer in a topic. **Example Scenario:** - You can track the status of a reputer’s pending stake removal request in the network. --- ## Get Total Stake Delegated to a Reputer - **RPC Method:** `GetStakeReputerAuthority` - **Command:** `reputer-authority [topic_id] [reputer]` - **Description:** Retrieves the total stake a reputer holds in a topic, including both their own stake and delegated stake. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `reputer`: The address of the reputer. ### Use Case: **Why use it?** - This command provides a complete view of a reputer's stake in a topic, combining both self-stake and delegated stake, which influences their standing in the network. **Example Scenario:** - Before interacting with a reputer in a topic, you may want to see their total stake, including how much has been delegated to them. --- ## Get Listening Coefficient for a Reputer - **RPC Method:** `GetListeningCoefficient` - **Command:** `listening-coefficient [topic_id] [reputer]` - **Description:** Returns the current [listening coefficient](https://docs.allora.network/learn/consensus-and-rewards#solution-adjusted-stake) for a given reputer in a specific topic. The coefficient measures how much a reputer is "listening" or interacting with the network. If no coefficient exists, it defaults to `1`. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `reputer`: The address of the reputer whose listening coefficient is being queried. ### Use Case: **Why use it?** - This command is useful to determine how actively a reputer is interacting with a topic. The listening coefficient reflects how engaged the reputer is in the network's consensus and decision-making process. **Example Scenario:** - As a delegator, you may want to check the listening coefficient of a reputer before deciding to delegate stake to them, ensuring they are actively participating in the topic. --- ## Get Multiple Reputers' Stakes in a Topic - **RPC Method:** `GetMultiReputerStakeInTopic` - **Command:** `multi-reputer-stake [addresses] [topic_id]` - **Description:** Retrieves the stakes for each reputer in a given list of addresses for a specific topic. The list can contain up to the `MaxPageLimit` number of addresses. If a reputer does not exist, their stake is defaulted to 0. - **Positional Arguments:** - `addresses`: A list of reputer addresses whose stakes you want to retrieve. - `topic_id`: The identifier of the topic. ### Use Case: **Why use it?** - This command allows you to query the stakes of multiple reputers in a specific topic in a single request, making it useful for bulk operations or analysis. **Example Scenario:** - You want to check the stakes of a list of reputers for a specific topic to compare their authority and influence in the topic. --- # Allora Forge Competitions Source: https://docs.allora.network/build/forge/competitions How Allora Forge competitions work — compete on live topics, build a testnet track record, and graduate to mainnet where top performers earn ALLO rewards. [Allora Forge](https://forge.allora.network) is the Allora Network's model competition platform: the hub where ML practitioners build, test, and deploy machine learning models against real-world data — competing for ALLO rewards while building an on-chain track record. Forge runs competitions on an ongoing basis. Each competition targets one live [topic](https://docs.allora.network/build/forge/topics) on the Allora Network, carries its own ALLO prize pool, and moves through **upcoming → active → ended** as its start and end dates pass. Browse [forge.allora.network](https://forge.allora.network) for the competitions that are open right now. ## How a competition works A competition ranks workers by their performance on its underlying topic. Topics run a continuous cycle: 1. **Submission window opens** — the network polls all registered workers on the topic for an inference. 2. **Workers respond** with a prediction; predictions lock when the window closes. 3. **Evaluation period** runs for the topic's time horizon (for example, 8 hours). 4. **Scores are revealed** — workers are ranked by loss against the ground truth, and rewards are distributed. The cycle repeats every epoch, so a competition is not a one-shot submission: your model keeps predicting for the duration of the competition window, and the leaderboard reflects its live, cumulative performance. ## Scoring Scoring happens on-chain. Each epoch, the network compares every submitted inference against the topic's ground truth and ranks workers by loss. Forge then summarizes that history into promotion-readiness metrics so you can see whether a worker has enough evidence of skill to move from testnet to mainnet. Promotion is evaluated **per worker, per topic**. A worker can be eligible on one topic and ineligible on another because the horizon, participation history, ground truth lag, and submitted inferences are topic-specific. The key dashboard detail is that some eligibility rows use a **confidence interval (CI)**, not only the point estimate shown as "your value." When a metric is displayed as: `your value (lower CI, upper CI)` the top-level value is the worker's point estimate for that metric. The values in parentheses are the confidence interval around that estimate. For promotion checks that say the **lower CI** must exceed a threshold, the relevant number is the **first value inside the parentheses**, not the top-level point estimate. For example, if directional accuracy appears as `72.3% (44.7%, 100%)`, the lower CI is `44.7%`; this would not pass a `> 50%` lower-bound threshold even though the point estimate is above 50%. Allora uses confidence intervals because workers may have different numbers of submissions. More submissions generally give more evidence and a tighter interval; fewer submissions leave more uncertainty. Where adjacent epochs share overlapping ground-truth windows, Allora corrects the interval calculation using an effective sample size so repeated, correlated observations do not overstate confidence. For mainnet promotion, a worker must pass every promotion metric on the topic: - **Effective sample size** — at least 20 raw effective observations - **Directional accuracy** — one-sided 95% lower CI greater than 50% - **Pearson correlation** — two-sided 95% lower CI greater than 0 - **WRMSE improvement** — adaptive lower CI greater than 0% - **WCZAR improvement** — adaptive lower CI greater than 0% - **Log aspect ratio** — confidence interval overlaps `[-0.5, +0.5]`, meaning forecast variation is not clearly too small or too large - **Participation** — strictly greater than 90% Long-horizon topics accumulate independent evidence more slowly, so the promotion system applies a forecast-horizon adjustment to directional accuracy, WRMSE improvement, and WCZAR improvement. This relaxes the effective confidence requirement for long horizons after the minimum effective-sample-size gate has already been met. Pearson correlation and log aspect ratio do not use this horizon adjustment. The [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit) mirrors this methodology off-chain: its `PerformanceEvaluator` grades your model against Allora's scoring methodology *before* you deploy, including directional accuracy, Pearson correlation, weighted-RMSE improvement, CZAR improvement, and related confidence checks. A higher grade means better generalization and a higher expected score on the network. For the full policy, including relegation criteria, see the Allora Research forum post on [inference worker promotion and relegation](https://research.allora.network/t/inference-worker-promotion-and-relegation/157). ### Log-return topics For log-return topics, the worker already submits the predicted log return, so no price conversion is needed before evaluation. The submitted prediction and the realized ground truth are compared in log-return space, and the promotion metrics above are calculated directly from that series. This makes log-return topics directly comparable with price topics after price forecasts have been converted into log returns. The zero baseline represents no change, and positive WRMSE or WCZAR improvement means the worker is improving over that baseline. ### Volatility topics Volatility topics are evaluated on the change in volatility, not the raw volatility level. Ground truth is calculated from one-minute log-price returns over trailing windows: - The base volatility covers the window ending at forecast time. - The target volatility covers the following horizon beginning at forecast time. - The evaluated change is the log ratio of target volatility to base volatility. Volatility naturally tends to mean-revert, which can inflate directional accuracy if it is not accounted for. Allora therefore estimates a causal trailing mean-reversion baseline from information available at forecast time and subtracts that expectation from both the worker prediction and the actual log-volatility change before calculating the evaluation metrics. Workers are evaluated on skill beyond that volatility baseline. ## From testnet to mainnet Workers start on **testnet** to establish a track record, then graduate to **mainnet**, where top performers earn ALLO token rewards. Your Forge dashboard tracks this progression as **Mainnet Readiness**: a set of per-worker criteria with an eligibility threshold. Meet enough criteria and the worker becomes eligible for mainnet promotion; until then the dashboard shows which criteria are still in progress. ## Compete 1. **Create a Forge account.** Sign up at [forge.allora.network](https://forge.allora.network) and connect a wallet to access your dashboard. 2. **Register.** Competition participation requires registering and getting whitelisted; the Forge site links to the registration form. 3. **Build and deploy a worker** on the competition's topic. The fastest path is the [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit), which takes you from historical data to a deployed worker — or follow the [price prediction worker walkthrough](https://docs.allora.network/build/worker/sdk-py) to do it with the Python SDK directly. 4. **Link your worker to your Forge account.** The builder kit's device flow signs with your on-disk worker key and links it to your account in the browser — your mnemonic never leaves your machine. Linked workers show up in your dashboard with their balance, earnings, and activity. 5. **Track your standing.** Forge shows per-topic leaderboards, the competitions you're in, and your workers' scores; the [Allora Explorer](https://explorer.allora.network) has the underlying on-chain detail. No whitelist yet? The testnet **playground topics** — the [sandbox topics 69 and 77](https://docs.allora.network/build/forge/topics#start-here-the-sandbox-topic) — are the recommended starting point and require no whitelist, so you can build, deploy, and score a worker end to end while your registration is pending. ## Build with the Forge Builder Kit The [Allora Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit) handles everything between your model and the network: - **Workflow API** — backfill historical data, engineer features, and build training datasets - **Evaluation** — grade your model against Allora's scoring methodology before deploying - **Deployment tooling** — wallet creation, faucet funding, and worker lifecycle management - **Monitoring dashboard** — web UI with submission history, on-chain scores, and live logs - **Topic discovery** — query all live topics on testnet and mainnet If you previously built models with the deprecated offchain node or Model Development Kit (MDK), see the [migration guide](https://docs.allora.network/build/migrate-from-offchain-node). Forge also exposes a programmatic API: create an API key from your Forge account to access it from scripts, CI pipelines, or your own services. ## Next - Pick a topic to compete on: [existing topics](https://docs.allora.network/build/forge/topics) - Deploy your first worker: [build a price prediction worker](https://docs.allora.network/build/worker/sdk-py) - Coming from the offchain node or MDK: [migrate to the Python SDK + Builder Kit](https://docs.allora.network/build/migrate-from-offchain-node) --- # Existing Allora Network Topics Source: https://docs.allora.network/build/forge/topics Live topic tables for Allora testnet and mainnet — topic IDs, metadata, epoch lengths, loss methods, and categories — plus how to verify a topic's status. > Topics currently active on the Allora Network The tables below list every topic that is **active** on each Allora network, with its topic ID, on-chain metadata (name), epoch length (in blocks), loss method, and category (price / log-return / volatility). Each [Forge competition](https://docs.allora.network/build/forge/competitions) targets one of these live topics. These tables are generated from live chain state, not maintained by hand. A scheduled job queries the [Cosmos LCD (REST) API](https://docs.allora.network/reference/networks) of each network (testnet `allora-testnet-1` via `emissions/v10`, mainnet `allora-mainnet-1` via `emissions/v9`), keeps only topics whose `is_topic_active` query returns `true`, and publishes the result at `/api/topics.json` — the same data this page renders. The data below last changed on **2026-07-31**. Topics activate and deactivate over time, so [verify a topic's status](#verify-a-topics-status) before building against it. ## Start here: the sandbox topic Testnet's sandbox topics are the no-penalty onboarding playground: somewhere to make your first worker submissions, with no whitelist required and nothing at stake if you get one wrong. - **69** — `PLAYGROUND: 1 day BTC/USD Price Prediction` - **77** — `PLAYGROUND FAST - 5 minute BTC/USD Price Prediction` The `PLAYGROUND FAST` topic is the short-epoch counterpart of the daily one, for quicker feedback while you iterate. Both are marked `sandbox` in the table below and carry a `sandbox` flag in `/api/topics.json`, which is where the list above is read from — so it cannot fall out of step with the tables. ## Testnet topics (`allora-testnet-1`) 39 active topics. | Topic ID | Metadata | Epoch Length (blocks) | Category | Loss Method | | --- | --- | --- | --- | --- | | 1 | ETH 10min Prediction | 120 | price | mse | | 2 | ETH 24h Prediction | 17280 | price | mse | | 3 | BTC 10min Prediction | 120 | price | mse | | 8 | BNB 20min Prediction | 240 | price | mse | | 9 | ARB 20min Prediction | 240 | price | mse | | 13 | ETH 5min Prediction | 60 | price | mse | | 14 | BTC 5min Prediction | 60 | price | mse | | 18 | BTC 8h Prediction | 5760 | price | mse | | 37 | SOL/USD - 5min Price Prediction | 35 | price | mse | | 38 | SOL/USD - 8h Price Prediction | 35 | price | mse | | 41 | ETH/USD - 8h Price Prediction | 35 | price | mse | | 42 | BTC/USD - 8h Price Prediction | 35 | price | mse | | 56 | 1 hour BERA/USD Log-Return Prediction | 655 | log-return | ztae | | 58 | 8 hour SOL/USD Log-Return Prediction | 52 | log-return | czar | | 60 | 24 hour XAU/USD Log-Return Prediction | 60 | log-return | czar | | 61 | 1 day BTC/USD Log-Return Prediction | 60 | log-return | czar | | 62 | 1 day SOL/USD Log-Return Prediction | 60 | log-return | czar | | 63 | 1 day ETH/USD Log-Return Prediction | 60 | log-return | czar | | 64 | 8h BTC/USD Log-Return Prediction (5min Updates) | 54 | log-return | czar | | 65 | 8h BTC/USD Log-Return Prediction (2h Updates) | 1286 | log-return | czar | | 66 | 7 day SOL/USD Log-Return Prediction | 720 | log-return | czar | | 67 | 7 day BTC/USD Log-Return Prediction | 720 | log-return | czar | | 68 | 7 day ETH/USD Log-Return Prediction | 720 | log-return | czar | | **69** (sandbox) | PLAYGROUND: 1 day BTC/USD Price Prediction | 54 | price | mse | | 70 | 7 day NEAR/USD Log-Return Prediction | 720 | log-return | czar | | 71 | 8 hour NEAR/USD Log-Return Prediction | 60 | log-return | czar | | 72 | 1 hour BTC/USD Log-Return Prediction | 60 | log-return | czar | | 73 | 1 hour ETH/USD Log-Return Prediction | 60 | log-return | czar | | 74 | 15 minute BTC/USD Log-Return Prediction | 60 | log-return | czar | | 75 | 15 minute ETH/USD Log-Return Prediction | 60 | log-return | czar | | 76 | 15 minute SOL/USD Log-Return Prediction | 60 | log-return | czar | | **77** (sandbox) | PLAYGROUND FAST - 5 minute BTC/USD Price Prediction | 60 | price | czar | | 79 | 15 minute BTC/USD - Volatility Prediction | 60 | volatility | mse | | 80 | 15 minute ETH/USD - Volatility Prediction | 60 | volatility | mse | | 81 | 15 minute XRP/USD - Volatility Prediction | 60 | volatility | mse | | 82 | 15 minute SOL/USD - Volatility Prediction | 60 | volatility | mse | | 83 | BTC/USD - Log Returns - 8h | 60 | log-return | czar | | 84 | ETH/USD - Log Returns - 8h | 60 | log-return | czar | | 85 | 4 hour ETH/USD - Volatility Prediction | 60 | volatility | mse | ## Mainnet topics (`allora-mainnet-1`) 15 active topics. | Topic ID | Metadata | Epoch Length (blocks) | Category | Loss Method | | --- | --- | --- | --- | --- | | 1 | BTC/USD - Log Returns - 8h | 75 | log-return | czar | | 2 | ETH/USD - Log Returns - 8h | 75 | log-return | czar | | 3 | SOL/USD - Log Returns - 8h | 75 | log-return | czar | | 9 | ETH/USD - Price Prediction - 8h | 60 | price | mse | | 10 | SOL/USD - Price Prediction - 8h | 60 | price | mse | | 14 | BTC/USD - Price Prediction - 8h | 60 | price | mse | | 15 | BTC/USD - Log Returns - 24h | 60 | log-return | czar | | 16 | ETH/USD - Log Returns - 24h | 60 | log-return | czar | | 17 | SOL/USD - Log Returns - 24h | 60 | log-return | czar | | 18 | BTC/USD - Log Returns - 20m | 60 | log-return | czar | | 19 | NEAR/USD - Log Returns - 8h | 60 | log-return | czar | | 20 | BTC/USD - Volatility - 15m | 60 | volatility | mse | | 21 | ETH/USD - Volatility - 15m | 60 | volatility | mse | | 22 | XRP/USD - Volatility - 15m | 60 | volatility | mse | | 23 | SOL/USD - Volatility - 15m | 60 | volatility | mse | **Warning**: Topic IDs are never guaranteed to be consistent between separate chains/deployments. The same prediction task can have different topic IDs on testnet and mainnet (for example, `BTC/USD - Log Returns - 8h` is topic 83 on testnet and topic 1 on mainnet). ## Verify a topic's status Query the live chain to confirm a topic's current definition and active status. Note that the `emissions` API version segment differs by network (see [Networks](https://docs.allora.network/reference/networks)): ```bash # Testnet (emissions/v10) curl -s https://allora-api.testnet.allora.network/emissions/v10/topics/69 curl -s https://allora-api.testnet.allora.network/emissions/v10/is_topic_active/69 # Mainnet (emissions/v9) curl -s https://allora-api.mainnet.allora.network/emissions/v9/topics/1 curl -s https://allora-api.mainnet.allora.network/emissions/v9/is_topic_active/1 ``` To consume the same list programmatically, fetch the published JSON instead of scraping this page: ```bash curl -s https://docs.allora.network/api/topics.json ``` ## Next - Deploy a worker on the sandbox topic: [build a price prediction worker](https://docs.allora.network/build/worker/sdk-py) - Compete on a live topic: [Forge competitions](https://docs.allora.network/build/forge/competitions) - Need a topic that doesn't exist yet? [Create your own](https://docs.allora.network/operate/topics/create) --- # Atlas Data Platform Source: https://docs.allora.network/build/atlas/overview Atlas is the Allora Forge timeseries data platform — discover datasets, query OHLCV candles at multiple resolutions, and stream live market data for model building. [Atlas](https://forge-data.allora.run) is the Allora Forge **timeseries data platform**: a hosted service where ML builders discover, query, and stream the market data that powers [Forge competitions](https://docs.allora.network/build/forge/competitions) and Allora [workers](https://docs.allora.network/build/worker/sdk-py). It is built for the model-building loop — backfill years of history for training, pull downsampled candles for feature engineering, and stream live rows at inference time — all through one REST API with one API key. Atlas gives you: - **A REST API** at `https://forge-data.allora.run/api` for datasets, columns, and rows — see the [Atlas API reference](https://docs.allora.network/build/atlas/api) - **Downsampled resolutions** — query raw data points or pre-computed `5m`, `1h`, and `1d` OHLCV aggregates with a single query parameter - **Bulk download** of historical ranges as JSON or CSV - **Real-time streaming** over Server-Sent Events (SSE) - **A web UI** at [forge-data.allora.run](https://forge-data.allora.run) to browse datasets, search metadata, and preview data in the browser (log in with your API key) - **Tag-based access control** so public datasets are one API call away ## The data model Atlas organizes everything into three resources: | Resource | What it is | |----------|------------| | **Dataset** | A named timeseries with a description and free-form JSON `metadata` (for example `source`, `ticker`, `frequency`) | | **Column** | A typed field of a dataset (for example `open`, `close`, `volume` as `float`) | | **Row** | One observation: a `timestamp` plus a `values` object with one entry per column | For example, `tiingo_btcusd_1min` is the 1-minute BTC/USD candle dataset. Its metadata identifies the source and frequency, and its seven float columns are `open`, `high`, `low`, `close`, `volume`, `volume_notional`, and `trades_done`: ```json { "id": 3, "name": "tiingo_btcusd_1min", "description": "Tiingo 1-minute OHLCV data for BTCUSD", "metadata": { "source": "tiingo", "ticker": "btcusd", "provider": "forge-data-provider", "frequency": "1min" } } ``` A raw row of that dataset looks like: ```json { "dataset_id": 3, "timestamp": "2026-07-30T21:59:00Z", "values": { "open": 64693.15622176585, "high": 64693.156307225116, "low": 64686.02040244367, "close": 64688.67038416061, "volume": 0.72766832, "volume_notional": 47071.896101475904, "trades_done": 134 } } ``` ### What data is available The catalog is large — over 980,000 datasets as of July 2026, discoverable by name and metadata search. The datasets most builders start with are the **Tiingo 1-minute crypto candles**: 77 USD pairs (`tiingo_btcusd_1min`, `tiingo_ethusd_1min`, `tiingo_solusd_1min`, …), continuously updated to within about a minute of real time. These are the same datasets the [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit) uses for its price-prediction workflows. Atlas also supports dataset creation and high-throughput ingest for data producers; this documentation covers the read and streaming API. ## Tag-based access Every dataset carries **tags**, and your API key holds tags too. You can read a dataset if you own it or if your key holds at least one of its tags: | Role | Read | Write | Manage tags | |------|------|-------|-------------| | Owner | Yes | Yes | Yes | | Key holds a matching tag | Yes | No | No | | No matching tag | No | No | No | Tags come in two kinds: - **Public tags** (for example `public`, `test`) — any key can self-acquire them with one API call. The Tiingo candle datasets are tagged `public`. - **Private tags** (for example `tiingo`, `premium`, `internal`) — restricted; they cannot be self-acquired. Acquiring the `public` tag is the first API call to make with a new key — the [API reference](https://docs.allora.network/build/atlas/api#step-1-acquire-the-public-tag) shows how, and the web UI and the Builder Kit's `AtlasDataManager` both do it automatically. ## Resolutions and range limits Row queries accept a `resolution` parameter. `raw` returns the original data points; the other resolutions return pre-computed OHLCV buckets (`open`, `high`, `low`, `close`, `volume`, plus a `count` of underlying points per bucket), which makes coarse queries fast and small. Each resolution enforces a maximum time range per request: | Resolution | Aggregation | Max range per request | |------------|-------------|-----------------------| | `raw` | None (original data points) | 24 hours | | `5m` | 5-minute OHLCV buckets | 7 days | | `1h` | 1-hour OHLCV buckets | 90 days | | `1d` | 1-day OHLCV buckets | Unlimited | Resolution controls how much data comes back: a week of 1-minute candles is ~10,000 raw rows but only 168 rows at `1h`. Ask for a range wider than the resolution allows and the API returns an error telling you to use a coarser resolution; if you omit `start`/`end`, it defaults to the most recent allowed window. For training-scale backfills of raw data, use [bulk download](https://docs.allora.network/build/atlas/api#bulk-download) and page through the history in chunks. ## Real-time streaming For live inference you don't need to poll. `GET /api/rows/stream/` holds the connection open as a **Server-Sent Events** stream: it sends a `connected` event, replays the most recent 100 rows as `data` events, then pushes each new row as it lands, with a `heartbeat` event every 30 seconds to keep the connection alive. See [the API reference](https://docs.allora.network/build/atlas/api#real-time-streaming-sse) for a working example. ## Authentication Atlas uses the same self-serve API keys as the rest of the Allora platform: sign up at the [Allora Developer Portal](https://developer.allora.network), create a key (prefixed `UP-`), and pass it in the `X-API-Key` header. Any Developer Portal key works — the same key you use for the [Allora API](https://docs.allora.network/consume/api) — and today every key gets the same access to public datasets. The tag system supports restricted tags, so tiered access may be introduced later. ## Next - Make your first queries: [Atlas API reference](https://docs.allora.network/build/atlas/api) - Put the data to work: [build a price prediction worker](https://docs.allora.network/build/worker/sdk-py) - Compete with your model: [Forge competitions](https://docs.allora.network/build/forge/competitions) --- # Atlas API Source: https://docs.allora.network/build/atlas/api Reference for the Atlas REST API at forge-data.allora.run — authentication, dataset discovery, row queries with resolutions, bulk download, SSE streaming, and Python access via the Forge Builder Kit. ## Goal Query the [Atlas data platform](https://docs.allora.network/build/atlas/overview) from the command line and from Python: discover datasets, fetch candles at any resolution, bulk-download history, and stream rows in real time. ## Prerequisites - An Allora API key — self-serve at the [Allora Developer Portal](https://developer.allora.network) (keys are prefixed `UP-`; the same key works for the [Allora API](https://docs.allora.network/consume/api)) - `curl` for the command-line examples; Python 3.10+ for the [Builder Kit examples](#python-atlasdatamanager) Export your key once and the examples below work as-is: ```bash export ALLORA_API_KEY="UP-..." ``` ## Base URL and authentication ``` https://forge-data.allora.run/api ``` Every endpoint requires the API key in the `X-API-Key` header: ```bash curl -H "X-API-Key: $ALLORA_API_KEY" "https://forge-data.allora.run/api/datasets/?limit=1" ``` Without the header you get `401 {"error":"Missing API key"}`. Endpoint paths end with a trailing slash (`/api/datasets/`, `/api/rows/`). List endpoints return Django REST Framework-style envelopes: `{"count": ..., "next": ..., "previous": ..., "results": [...]}`. ## Step 1: acquire the public tag Datasets are protected by [tags](https://docs.allora.network/build/atlas/overview#tag-based-access). A fresh key holds no tags, so acquire the `public` tag first — one idempotent call: ```bash curl -X POST "https://forge-data.allora.run/api/tags/acquire/" \ -H "X-API-Key: $ALLORA_API_KEY" \ -H "Content-Type: application/json" \ -d '{"tag_name": "public"}' ``` ```json {"message": "Tag acquired successfully"} ``` Re-running it on a key that already holds the tag returns `409` — safe to ignore. The Atlas web UI and the Builder Kit's `AtlasDataManager` both do this automatically. ## Step 2: find a dataset `GET /api/datasets/` lists the datasets your key can see. It supports free-text `search` over names and descriptions, plus `limit`/`offset` pagination (the response's `next` field carries the pre-built URL for the following page): ```bash curl -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/datasets/?search=tiingo_btcusd_1min&limit=5" ``` ```json { "count": 1, "next": null, "previous": null, "results": [ { "id": 3, "name": "tiingo_btcusd_1min", "description": "Tiingo 1-minute OHLCV data for BTCUSD", "metadata": { "source": "tiingo", "ticker": "btcusd", "provider": "forge-data-provider", "frequency": "1min" }, "created_at": "2026-01-26T19:17:33.793195Z", "updated_at": "2026-01-26T19:17:33.795326Z" } ] } ``` If this returns your dataset, your key and tag are working — every other endpoint uses the same auth. Fetch a single dataset by ID with `GET /api/datasets/{id}/`. ### Metadata search `GET /api/datasets/search/` filters on any metadata field by exact value: ```bash curl -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/datasets/search/?ticker=btcusd" ``` This returns every dataset whose `metadata.ticker` is `btcusd`. Pass **one** metadata filter per request. Combining filters (for example `?source=tiingo&ticker=btcusd`) currently returns an error — `"multiple metadata filters are temporarily unsupported"` — a limitation that is planned to be removed. Until then, filter on one field and narrow further client-side. ### Columns `GET /api/columns/?dataset={id}` lists a dataset's typed columns: ```bash curl -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/columns/?dataset=3" ``` ```json { "count": 7, "next": null, "previous": null, "results": [ {"id": 3, "dataset_id": 3, "name": "open", "dtype": "float", "created_at": "2026-01-26T19:17:33.934814Z"}, {"id": 4, "dataset_id": 3, "name": "high", "dtype": "float", "created_at": "2026-01-26T19:17:34.006085Z"} ] } ``` *(Response truncated — `tiingo_btcusd_1min` has seven float columns: `open`, `high`, `low`, `close`, `volume`, `volume_notional`, `trades_done`.)* ## Step 3: query rows `GET /api/rows/` is the core query endpoint: | Param | Description | |-------|-------------| | `dataset` / `dataset_name` | Dataset ID or name — one of the two is required | | `start` / `end` | Time range bounds, RFC 3339 (`2026-07-30T00:00:00Z`) | | `resolution` | `raw` (default), `5m`, `1h`, or `1d` — non-raw values query pre-computed OHLCV aggregates | | `limit` / `offset` | Offset pagination (default limit 250, max 10,000) | | `after` | Cursor pagination — a timestamp; the response's `next` URL has the following cursor pre-filled | | `ordering` | `timestamp` ascending, `-timestamp` descending | Latest raw rows: ```bash curl -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/rows/?dataset_name=tiingo_btcusd_1min&limit=2&ordering=-timestamp" ``` ```json { "count": -1, "next": null, "previous": null, "results": [ { "id": 910254487, "dataset_id": 3, "timestamp": "2026-07-30T21:59:00Z", "created_at": "2026-07-30T22:00:00.376191Z", "values": { "open": 64693.15622176585, "high": 64693.156307225116, "low": 64686.02040244367, "close": 64688.67038416061, "volume": 0.72766832, "volume_notional": 47071.896101475904, "trades_done": 134 } } ] } ``` *(Response truncated to the first row.)* `count` is the total matching rows, with two caveats: on very large datasets the count query can time out and return `count: -1` (the data itself is unaffected), and cursor-paginated responses always report `count: 0`. Treat `next: null` — not `count` — as the end-of-data signal. ### Downsampled resolutions Add `resolution` to get OHLCV buckets instead of raw points. Buckets carry `open`, `high`, `low`, `close`, `volume`, and `count` (data points per bucket) at the top level: ```bash curl -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/rows/?dataset_name=tiingo_btcusd_1min&resolution=1h&limit=3&ordering=-timestamp" ``` ```json { "count": 2145, "next": "/api/rows/?dataset_name=tiingo_btcusd_1min&limit=3&offset=3&ordering=-timestamp&resolution=1h", "previous": null, "results": [ { "dataset_id": 3, "timestamp": "2026-07-30T19:00:00Z", "open": 64640.87525369247, "high": 64844.579994222186, "low": 64639.41675187879, "close": 64741.70195346407, "volume": 589.7614337300001, "count": 60 } ] } ``` *(Response truncated to the first bucket.)* Each resolution caps the time range of a single request — `raw` 24 hours, `5m` 7 days, `1h` 90 days, `1d` unlimited (see [range limits](https://docs.allora.network/build/atlas/overview#resolutions-and-range-limits)). Omit `start`/`end` and the query defaults to the most recent allowed window; exceed the cap and you get: ```json {"details": null, "error": "time range exceeds maximum of 24h0m0s for resolution=raw; use a coarser resolution: bad request"} ``` ### Cursor pagination For iterating large ranges, cursor pagination is O(1) per page — pass `after` with the last timestamp you've seen and follow `next` until it is `null`: ```bash curl -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/rows/?dataset_name=tiingo_btcusd_1min&after=2026-07-30T21:55:00Z&limit=2&ordering=timestamp" ``` ```json { "count": 0, "next": "/api/rows/?after=2026-07-30T21%3A57%3A00Z&dataset_name=tiingo_btcusd_1min&limit=2&ordering=timestamp", "previous": null, "results": [ {"timestamp": "2026-07-30T21:56:00Z", "...": "..."}, {"timestamp": "2026-07-30T21:57:00Z", "...": "..."} ] } ``` *(Row bodies elided for brevity — same shape as the raw rows above.)* ## Bulk download `GET /api/rows/bulk_download/` streams a whole time range in one response — the efficient path for backfills. It takes the same `dataset`/`dataset_name`, `start`, `end`, and `resolution` params plus `output` (`json`, the default, or `csv`): ```bash curl -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/rows/bulk_download/?dataset_name=tiingo_btcusd_1min&start=2026-07-29T00:00:00Z&end=2026-07-30T00:00:00Z&resolution=1h&output=csv" ``` ```csv timestamp,open,high,low,close,volume,count 2026-07-29T00:00:00Z,63852.09935765776,64111.03020276603,63781.73958167701,63878.08438839432,408.84284353,60 2026-07-29T01:00:00Z,63882.10637273496,63931.58154694832,63600.25928414847,63626.41042882476,318.66601494999986,60 ``` *(Output truncated to the first two of 24 hourly buckets.)* With `output=json` (or omitted) the same query returns a flat JSON array of row objects. For multi-month raw backfills, request the history in chunks (the Builder Kit's `backfill_symbol` does 14-day chunks with retry and split-on-failure for you). ## Recent rows as NDJSON `GET /api/rows/live/` returns the most recent rows (newest first) as newline-delimited JSON — one flat object per line, convenient for piping into other tools. `limit` defaults to 100 (max 10,000); optional `start`/`end` bound the window: ```bash curl -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/rows/live/?dataset_name=tiingo_btcusd_1min&limit=3" ``` ```json {"close":64688.67038416061,"high":64693.156307225116,"low":64686.02040244367,"open":64693.15622176585,"timestamp":"2026-07-30T21:59:00Z","trades_done":134,"volume":0.72766832,"volume_notional":47071.896101475904} {"close":64682.63723244969,"high":64685.826365674286,"low":64682.054250911155,"open":64682.66244872556,"timestamp":"2026-07-30T21:58:00Z","trades_done":187,"volume":1.3486775199999999,"volume_notional":87236.0187697199} {"close":64679.00000395987,"high":64691.12448888278,"low":64646.852832919416,"open":64651.0093708298,"timestamp":"2026-07-30T21:57:00Z","trades_done":366,"volume":2.48801944,"volume_notional":160922.6093696122} ``` ## Real-time streaming (SSE) `GET /api/rows/stream/` holds the connection open as a **Server-Sent Events** stream (`Content-Type: text/event-stream`). It takes `dataset` or `dataset_name`: ```bash curl -N -H "X-API-Key: $ALLORA_API_KEY" \ "https://forge-data.allora.run/api/rows/stream/?dataset_name=tiingo_btcusd_1min" ``` ``` event: connected data: {"dataset_id":3,"message":"Connected to real-time stream"} event: data data: {"close":64780.30788599765,"high":64783.650443566934,"low":64760.977618071105,"open":64760.980970991615,"timestamp":"2026-07-30T20:20:00Z","trades_done":320,"volume":3.64579031,"volume_notional":236175.41876958683} event: heartbeat data: {"timestamp":"2026-07-30T22:06:43Z"} ``` The stream sends, in order: 1. One `connected` event confirming the subscription 2. The most recent 100 rows replayed as `data` events (oldest first), so a fresh consumer starts with context 3. A `data` event for each new row as it is ingested 4. A `heartbeat` event every 30 seconds to keep the connection alive Use any SSE client (`EventSource` in the browser, `curl -N` in scripts) and reconnect on disconnect. ## Tags and access Beyond [`POST /api/tags/acquire/`](#step-1-acquire-the-public-tag): ```bash # List all tags (public ones are self-acquirable) curl -H "X-API-Key: $ALLORA_API_KEY" "https://forge-data.allora.run/api/tags/" # List a dataset's tags curl -H "X-API-Key: $ALLORA_API_KEY" "https://forge-data.allora.run/api/datasets/3/tags/" # Check what access your key has to a dataset curl -X POST "https://forge-data.allora.run/api/access/check/" \ -H "X-API-Key: $ALLORA_API_KEY" \ -H "Content-Type: application/json" \ -d '{"dataset_id": 3, "require_write": false}' ``` The access check answers with your effective permissions and which tags granted them: ```json {"has_access": true, "is_owner": false, "matching_tags": ["public"]} ``` ## Python: AtlasDataManager The [Allora Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit) ships `AtlasDataManager`, a high-level client that handles tag acquisition, dataset resolution by ticker, chunked backfills into partitioned Parquet files, and live snapshots. Install it: ```bash pip install "git+https://github.com/allora-network/allora-forge-builder-kit.git" websocket-client ``` Then, with `ALLORA_API_KEY` exported as above: ```python import os from datetime import datetime, timedelta, timezone from allora_forge_builder_kit import AtlasDataManager manager = AtlasDataManager( api_key=os.environ["ALLORA_API_KEY"], interval="5m", symbols=["BTC/USD"], ) # Discover the Tiingo 1-minute datasets you can access datasets = manager.list_available_datasets(source="tiingo", frequency="1min") print([ds["name"] for ds in datasets]) # Fetch the most recent hour of 1-minute bars as a DataFrame df = manager.get_live_1min_data("BTC/USD", hours_back=1) print(df.tail()) # Backfill a day of history into partitioned Parquet files start = datetime.now(timezone.utc) - timedelta(days=1) manager.backfill_symbol("BTC/USD", start=start) ``` On first use the constructor acquires the `public` tag for your key automatically. Tickers like `"BTC/USD"` are resolved to datasets named `tiingo_btcusd_1min`. The methods you'll reach for: | Method | What it does | |--------|--------------| | `list_available_datasets(source, frequency)` | List datasets for a source/frequency (default `tiingo` / `1min`) | | `search_datasets(query)` | Free-text search across dataset names and descriptions | | `get_live_1min_data(symbol, hours_back)` | Most recent 1-minute bars as a pandas DataFrame, lag-tolerant | | `get_live_snapshot(symbols)` | Latest completed bar per symbol at the manager's `interval` | | `backfill_symbol(symbol, start, end)` | Chunked bulk download into per-day Parquet partitions, with retry and split-on-failure | `AtlasDataManager` refuses base URLs outside `forge-data.allora.run` to protect your API key from being sent elsewhere, and plugs directly into the Builder Kit's `AlloraMLWorkflow` for feature engineering and model training — see [Forge competitions](https://docs.allora.network/build/forge/competitions) for that path. ## Troubleshoot - **`401 {"error":"Missing API key"}`** — the key goes in the `X-API-Key` header. Check `echo $ALLORA_API_KEY` prints your key. - **Dataset not found or missing from listings** — a fresh key sees nothing until it holds a tag. Run [step 1](#step-1-acquire-the-public-tag), then retry. - **`time range exceeds maximum of ... for resolution=...`** — narrow the `start`/`end` window, pick a coarser resolution, or chunk the range via [bulk download](#bulk-download). - **`multiple metadata filters are temporarily unsupported`** — `/api/datasets/search/` takes one metadata filter per request; filter further client-side. - **`count` is `-1` or `0` but rows are returned** — expected: `-1` means the total-count query timed out on a huge dataset, `0` is normal for cursor pagination. Follow `next` until `null`. - **SSE stream goes quiet** — heartbeats arrive every 30 seconds; if they stop, the connection dropped. Reconnect (you'll get the 100-row replay again, so deduplicate by `timestamp`). - **`ModuleNotFoundError: No module named 'websocket'` on import** — install `websocket-client` alongside the Builder Kit (it is required by the package's top-level imports). ## Next - The concepts behind the API: [Atlas overview](https://docs.allora.network/build/atlas/overview) - Feed the data into a model: [build a price prediction worker](https://docs.allora.network/build/worker/sdk-py) - Deploy against a live topic: [Forge competitions](https://docs.allora.network/build/forge/competitions) --- # Migrate from the Offchain Node Source: https://docs.allora.network/build/migrate-from-offchain-node Move a worker off the deprecated allora-offchain-node + Model Development Kit stack onto the Allora Python SDK and the Forge Builder Kit. The original worker stack — the [`allora-offchain-node`](https://github.com/allora-network/allora-offchain-node) Go daemon configured through `config.json`, relaying inferences from a separate HTTP inference server, with models trained and packaged by the Model Development Kit (MDK) — is **deprecated** for workers. The replacement is: - The [Allora Python SDK](https://docs.allora.network/consume/sdk-py) (`allora_sdk`): its `AlloraWorker` calls your model as a Python function in the same process and submits the result on-chain. It handles wallet creation, registration, testnet faucet funding, fee estimation, and retries — no Go daemon, no `config.json`, no HTTP relay between your model and the network. - The [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit): replaces the MDK's train/eval/package workflow with `AlloraMLWorkflow` (historical data backfill, feature engineering, training datasets), `PerformanceEvaluator` (grades your model against Allora's scoring methodology before you deploy), and `WorkerManager` (wallet creation, faucet funding, worker lifecycle) plus a web monitoring dashboard. ## Goal Replace an `allora-offchain-node` worker with a Python SDK worker that keeps the same wallet and topic, and replace an MDK model workflow with the Forge Builder Kit. ## Prerequisites - Python 3.10–3.13 for the SDK (the Builder Kit's install instructions use Python 3.11) - Your existing `config.json`, for the values you will carry over: - `wallet.addressRestoreMnemonic` — only if you want to keep your existing `allo...` address; otherwise the SDK generates a fresh identity - `worker[].topicId` for each topic you serve - An Allora API key — free at [developer.allora.network](https://developer.allora.network). On testnet, the worker uses it to request ALLO gas from the faucet automatically. The published SDK release (`allora_sdk` 1.3.0) also covers reputers: `AlloraWorker.reputer(...)` takes a reputer function built from your ground-truth and loss functions via `make_reputer_function(get_ground_truth, loss_fn)`, and `min_stake_uallo` replaces the offchain node's `minStake` — see [Build a Reputer](https://docs.allora.network/build/reputer/build-a-reputer). The offchain node also continues to run reputers. ## Steps ### 1. Map your `config.json` to `AlloraWorker` The offchain node was configured with a `config.json` (see `config.example.json` in the repository). Everything it configured is either a constructor argument to `AlloraWorker.inferer()` or handled automatically: | `config.json` (offchain node) | Python SDK (`AlloraWorker.inferer(...)`) | | :--- | :--- | | `wallet.addressRestoreMnemonic` | `wallet=AlloraWalletConfig(mnemonic=...)` — or omit `wallet` and the worker generates an identity, saved to a `.allora_key` file and reused on later runs | | `wallet.addressKeyName`, `wallet.keyringBackend`, `wallet.alloraHomeDir` | Not needed — the SDK does not use the `allorad` keyring | | `wallet.chainId` | `network=AlloraNetworkConfig(chain_id=...)` — or use the presets `AlloraNetworkConfig.testnet()` / `.mainnet()` | | `wallet.nodeRpcs`, `wallet.nodegRpcs` | `network=AlloraNetworkConfig(url=..., websocket_url=...)` — a `grpc+https://` URL uses gRPC, `rest+https://` uses the Cosmos-LCD REST API | | `wallet.gasPrices`, `wallet.maxFees`, `wallet.gasAdjustment` | `fee_tier=FeeTier.ECO` / `.STANDARD` (default) / `.PRIORITY` — fee estimation is automatic | | `wallet.maxRetries`, `wallet.retryDelay`, `wallet.accountSequenceRetryDelay` | Handled automatically — retries are built in | | `wallet.submitTx` | Not needed — the worker submits transactions; use the [RPC client](https://docs.allora.network/consume/sdk-py#allorarpcclient-typed-chain-queries-and-transactions) directly for query-only use | | `worker[].topicId` | `topic_id=...` | | `worker[].inferenceEntrypointName` + `worker[].parameters.InferenceEndpoint` / `Token` | `run=...` — your model is a Python function called in-process; there is no HTTP inference server to stand up | | Multiple entries in the `worker` array | One `AlloraWorker.inferer(...)` per topic — or let the Builder Kit's `WorkerManager` run one worker process per topic | | `init.config` + `docker compose up --build` | `python worker.py` | | `reputer[]` | `AlloraWorker.reputer(...)` — `groundTruthEntrypointName` + `lossFunctionEntrypointName` become Python functions combined with `make_reputer_function(get_ground_truth, loss_fn)`, and `minStake` becomes `min_stake_uallo` — see [Build a Reputer](https://docs.allora.network/build/reputer/build-a-reputer) | ### 2. Rewrite the worker as a Python script Install the SDK: ```bash pip install allora_sdk ``` Save this as `worker.py`. The body of `run_model` is where the logic behind your old `InferenceEndpoint` goes — return the value your inference server used to serve over HTTP: ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext from allora_sdk.rpc_client.config import AlloraWalletConfig async def run_model(ctx: RunContext) -> float: # The prediction logic your inference server exposed over HTTP goes here return 123.45 async def main(): worker = AlloraWorker.inferer( run=run_model, # Your worker[].topicId from config.json topic_id=69, network=AlloraNetworkConfig.testnet(), # Keep your existing address: reuse wallet.addressRestoreMnemonic from config.json. # Omit `wallet=` to generate a fresh identity instead. wallet=AlloraWalletConfig(mnemonic=os.environ["ALLORA_WALLET_MNEMONIC"]), api_key=os.environ["ALLORA_API_KEY"], ) async for result in worker.run(): if isinstance(result, Exception): print(f"Inference worker error: {result}") else: print(f"Prediction submitted to Allora: {result.submission}") asyncio.run(main()) ``` Run it: ```bash export ALLORA_WALLET_MNEMONIC="" export ALLORA_API_KEY="" python worker.py ``` If you served multiple topics from one `config.json` `worker` array, run one script per topic with its own `topic_id`. The [Python SDK page](https://docs.allora.network/consume/sdk-py) covers the full set of options (`fee_tier`, `polling_interval`, `debug`, custom `AlloraNetworkConfig`). ### 3. Move your model workflow from the MDK to the Builder Kit The MDK's interactive `make` targets map onto the Builder Kit's Python API: | MDK workflow | Forge Builder Kit workflow | | :--- | :--- | | `make train` — interactive prompts for a Tiingo or CSV data source, symbol, interval, date range, and models | `AlloraMLWorkflow(tickers=[...], topic_id=..., interval=..., n_input_bars=..., n_target_bars=...)`, then `workflow.backfill(days=...)` and `workflow.get_full_feature_target_dataframe()` — datasets are keyed to live Allora topics (use `data_source="binance"` if you have no API key) | | `make eval` — MAE / RMSE reports | `PerformanceEvaluator(workflow).evaluate(predict_fn)` — 7 pass/fail metrics aligned with Allora's scoring methodology (directional accuracy, Pearson r, WRMSE, CZAR) and a letter grade | | `make package-` — copies model files and generates `config.py` | The example walkthrough scripts train a model and save a `predict.pkl` artifact | | `MODEL= make run` + `uvicorn main:app` — expose an HTTP inference endpoint, then wire it into the offchain node's `config.json` | `python deploy_worker.py` — `WorkerManager` creates a wallet, requests testnet ALLO from the faucet, and starts the worker process; no endpoint to expose | | `make node-env` + `make compose` — load config and start the Docker node | `WorkerManager` start/stop/status APIs, plus a web dashboard: `python -m allora_forge_builder_kit.web_dashboard` at http://localhost:8787 | To get started: ```bash git clone https://github.com/allora-network/allora-forge-builder-kit.git cd allora-forge-builder-kit python3.11 -m venv .venv source .venv/bin/activate python -m pip install . python -m pip install -r requirements.txt ``` Then follow the repository's "Zero to deploy" walkthrough: train an example model on the sandbox topic (`notebooks/example_topic_69_bitcoin_walkthrough.py`), deploy it (`python deploy_worker.py`), and monitor it from the dashboard. ## Verify - Your worker logs its `allo...` address and prints `Prediction submitted to Allora: ...` each time a submission window opens — this replaces the offchain node's `"Send Worker Data to chain" ... "message":"Success"` log line. - If you reused your mnemonic, confirm the logged address matches the one your offchain node registered. - Open your topic on the [testnet explorer](https://testnet.explorer.allora.network/topics/69) and look for your worker's address among the topic's workers. - Builder Kit deployments: the web dashboard at http://localhost:8787 shows each worker's submission timeline, on-chain scores, and live log tail. ## Troubleshoot - **Worker prompts `Mnemonic:` on startup** — no wallet was configured and no `.allora_key` file exists yet. Paste your `wallet.addressRestoreMnemonic` to keep your old address, or press Enter to generate a fresh identity. - **`RuntimeError: asyncio.run() cannot be called from a running event loop`** — you are in a Jupyter/Colab notebook. Replace `asyncio.run(main())` with `await main()`. - **`Too many faucet requests`** — the testnet faucet is rate-limited. Your old worker wallet likely still holds ALLO; reuse it via `ALLORA_WALLET_MNEMONIC`, or request funds manually at [faucet.testnet.allora.network](https://faucet.testnet.allora.network). - **You run a reputer** — migrate it to `AlloraWorker.reputer(...)` ([Build a Reputer](https://docs.allora.network/build/reputer/build-a-reputer)), or keep your `reputer` configuration on the offchain node — it still runs reputers. - **Builder Kit worker fails to start** — faucet activity is logged, not printed: check `worker_logs/` for the subprocess output (faucet requests, balance checks, on-chain errors). ## Next - See a full worker build, from data to deployment: [build a worker with the Python SDK](https://docs.allora.network/build/worker/sdk-py) - Compete with your model: [Forge competitions](https://docs.allora.network/build/forge/competitions) - Full worker, RPC, and API client reference: [Allora Python SDK](https://docs.allora.network/consume/sdk-py) - Pick a topic to serve: [existing topics](https://docs.allora.network/build/forge/topics) --- # Consumers Source: https://docs.allora.network/consume/overview Consumers are entities that utilize the inferences generated by the network. Consumers are entities that utilize the inferences generated by the network. These consumers can take various forms, from individuals or organizations making use of inference data to automated contracts that interact with the blockchain. **On-chain consumer contracts are being rebuilt.** Documentation for deploying and integrating consumer contracts will return when the new contracts ship. In the meantime, consume inferences through the [Allora API](https://docs.allora.network/consume/api) or via [RPC](https://docs.allora.network/consume/rpc-grpc). ## Distinction between Consumers and Consumer Contracts ### Consumers Consumers are all-encompassing actors that consume inferences on the Allora Network. These could be businesses, developers, data scientists, or any entity interested in the intelligence generated by the network. ### Consumer Contracts Consumer contracts are blockchain-deployed contracts that consume inferences. These smart contracts automatically interact with the network to retrieve inference data and use it within their logic. For example, a decentralized finance (DeFi) application might use consumer contracts to obtain and act upon real-time price predictions for cryptocurrencies. --- # Allora API: How to Query Data of Existing Topics Source: https://docs.allora.network/consume/api The Allora API provides an interface to query real-time on-chain data of the latest inferences made by workers. The **Allora API** provides an interface to query real-time on-chain data of the latest inferences made by workers. Here's an explanation of how it works using the example endpoint: ## API Authentication To access the Allora API, you need to authenticate your requests using an API key. ### Obtaining an API Key API keys are self-serve: sign up for a free account at the [Allora Developer Portal](https://developer.allora.network) and create an API key from your dashboard. API keys are prefixed with `UP-`. The same API key works for both the Allora API (`api.allora.network`) and the Atlas data platform (`forge-data.allora.run`). ### Using an API Key Once you have an API key, you can include it in your API requests using the `x-api-key` header: ```bash curl -X 'GET' \ --url 'https://api.allora.network/v2/allora/consumer/?allora_topic_id=' \ -H 'accept: application/json' \ -H 'x-api-key: ' ``` Replace `` with your actual API key, `` with a supported chain ID (see the `SignatureFormat` values in the [TypeScript SDK reference](https://docs.allora.network/consume/sdk-ts) for supported values), and `` with the topic ID you want to query. ### API Key Security Your API key is a sensitive credential that should be kept secure. Do not share your API key or commit it to version control systems. Instead, use environment variables or secure credential storage mechanisms to manage your API key. ```javascript // Example of using an environment variable for API key const apiKey = process.env.ALLORA_API_KEY; ``` ### Rate Limiting API requests are subject to rate limiting. If you exceed the rate limit, you will receive a 429 Too Many Requests response. To avoid rate limiting issues, consider implementing retry logic with exponential backoff in your applications. ## API Endpoints **Generic**: `https://allora-api.testnet.allora.network/emissions/{version_number}/latest_network_inferences/{topic_id}` **Example**: `https://allora-api.testnet.allora.network/emissions/v10/latest_network_inferences/1` Where: - "v10" is the `emissions` API version, which depends on the deployed chain version of the network you are querying (testnet = `v10`, mainnet = `v9`). See [Networks](https://docs.allora.network/reference/networks) for the current version per network. - "1" represents the topic ID An **outlier-resistant** variant is available for single-label regression topics: **Outlier-resistant**: `https://allora-api.testnet.allora.network/emissions/v10/latest_network_inferences_outlier_resistant/{topic_id}` Sample Response (single-output regression topic): ```json { "network_inferences": { "topic_id": "1", "nonce": "1349577", "combined_value": [ { "label_id": 1, "label_name": "y", "value": "2605.533879185080648394998043723508" } ], "inferer_values": [ { "worker": "allo102ksu3kx57w0mrhkg37kvymmk2lgxqcan6u7yn", "values": [ { "label_id": 1, "label_name": "y", "value": "2611.01109296" } ] }, { "worker": "allo10q6hm2yae8slpvvgmxqrcasa30gu5qfysp4wkz", "values": [ { "label_id": 1, "label_name": "y", "value": "2661.505295679922" } ] } ], "forecaster_values": [ { "worker": "allo1za8r9v0st4ntfyeka23qs5wvd7mvsnzhztupk0", "values": [ { "label_id": 1, "label_name": "y", "value": "2610.160000000000000000000000000000" } ] } ], "naive_value": [ { "label_id": 1, "label_name": "y", "value": "2605.533879185080648394998043723508" } ], "one_out_inferer_values": [ { "withheld_inferer": "allo102ksu3kx57w0mrhkg37kvymmk2lgxqcan6u7yn", "combined_inference": [ { "label_id": 1, "label_name": "y", "value": "2570.859434973857748387096774193548" } ] } ], "one_out_forecaster_values": [], "one_in_forecaster_values": [], "one_out_inferer_forecaster_values": [] }, "inference_block_height": "1349577" } ``` Since v0.17.0 the network inference is returned as a **labeled bundle**. Every value carries a `label_id` and `label_name`. A **single-output** topic (like the one above) always uses the canonical label `y`, so each array holds a single entry. A **multi-output / classification** topic returns one entry per label — for example `combined_value` might contain `{ "label_name": "up", ... }`, `{ "label_name": "down", ... }`, and `{ "label_name": "flat", ... }`. Please be aware that there may be some expected volatility in predictions due to the nascency of the network and the more forgiving testnet configurations currently in place. We are actively working on implementing an outlier protection mechanism, which will be applied at the consumer layer and tailored to individual use cases in the near future. ## Breaking Down the Response Below is an explanation of the important fields in the JSON output. Every inference value is **labeled** (`label_id` + `label_name` + `value`); single-output topics use the canonical label `y`. ### `topic_id` In this case, "1" represents the topic being queried. [Topics](https://docs.allora.network/operate/topics/create) define the context and rules for a particular inference. ### `combined_value` The **combined value** is an optimized inference that represents a collective intelligence approach, taking both worker submissions and forecast data into account. > If you are looking to just get one value or number from Allora for a data oracle, this is the one to take (for a single-output topic, the entry labeled `y`). ### `inferer_values` Workers in the network submit their inferences, each represented by an `allo` address and one value per label. For example: ```json { "worker": "allo102ksu3kx57w0mrhkg37kvymmk2lgxqcan6u7yn", "values": [ { "label_id": 1, "label_name": "y", "value": "2611.01109296" } ] } ``` Each worker submits values based on their own models. These individual submissions contribute to both the naive and combined values. The combined value gives higher weighting to more reliable workers, based on performance or other criteria. ### `forecaster_values` The forecast-implied inferences, one per forecaster. A [forecast-implied inference](https://docs.allora.network/learn/inference-synthesis#forecast-implied-inferences) uses forecasted losses and worker inferences to produce a predicted value, weighted by how accurately each forecaster predicted losses in previous epochs. ### `naive_value` The **naive value** omits all forecast-implied inferences from the weighted average by setting their weights to zero. It is used to quantify the contribution of the forecasting task to network accuracy, which in turn sets the reward distribution between the inference and forecasting tasks. ### `one_out_inferer_values` / `one_out_forecaster_values` / `one_in_forecaster_values` These simulate removing (or adding) a single participant to measure their marginal impact on the combined inference. They are used for scoring and reward distribution. ### `inference_block_height` The specific chain block at which the inference data was generated. Per-actor **weights** and **confidence intervals** are not part of this response. Weights can be queried separately (for example `GetLatestInfererWeight` / `GetLatestForecasterWeight`), and confidence intervals are described on the [Confidence Intervals](https://docs.allora.network/learn/confidence-intervals) page. --- # Allora SDKs Source: https://docs.allora.network/consume/sdk-overview Choose the right Allora SDK — the Python worker framework for submitting predictions, or the Python, TypeScript, and Go clients for consuming inferences. Allora ships SDKs in Python, TypeScript, and Go. Which one you need depends on which side of the network you are on: - **Building models?** Workers *produce* inferences. The [Python SDK](https://docs.allora.network/consume/sdk-py)'s `AlloraWorker` is the worker framework: it wraps wallet management, topic registration, submission windows, and transaction retries around your prediction function. Start with the [worker guide](https://docs.allora.network/build/worker/sdk-py). - **Consuming inferences?** Consumers *read* what the network produces — topics, network inferences, signed price predictions. All three SDKs cover this: pick the language that matches your stack from the table below, or start with the hands-on [Consume an inference in 2 minutes](https://docs.allora.network/get-started/quickstart-consume) quickstart. ## Capabilities by language | Capability | [Python](https://docs.allora.network/consume/sdk-py) | [TypeScript](https://docs.allora.network/consume/sdk-ts) | [Go](https://docs.allora.network/consume/sdk-go) | | :--- | :---: | :---: | :---: | | Read topics and latest network inferences (Allora API) | ✓ | ✓ | ✓ | | Signed inferences for on-chain (EVM) verification | ✓ | ✓ | — | | Price prediction helpers (BTC/ETH by timeframe) | — | ✓ | — | | Typed chain queries (emissions and Cosmos modules) | ✓ | — | ✓ | | Chain event subscriptions (WebSocket) | ✓ | — | ✓ | | Endpoint load balancing and failover | — | — | ✓ | | Historical OHLC market data | — | — | ✓ | | Wallets and transaction submission | ✓ | — | ✓ | | Worker framework (submit predictions) | ✓ | — | — | ## Installation | Language | Package | Install | | :--- | :--- | :--- | | Python | [`allora_sdk`](https://pypi.org/project/allora-sdk/) | `pip install allora_sdk` | | TypeScript | [`@alloralabs/allora-sdk`](https://www.npmjs.com/package/@alloralabs/allora-sdk) | `npm install @alloralabs/allora-sdk` | | Go | [`allora-sdk-go`](https://github.com/allora-network/allora-sdk-go) | `go get github.com/allora-network/allora-sdk-go` | All three use the same free API key from [developer.allora.network](https://developer.allora.network) for Allora API access. ## Which should I use? - **ML builders** submitting predictions: the [Python SDK](https://docs.allora.network/consume/sdk-py) is the only SDK with the worker framework — follow the [worker guide](https://docs.allora.network/build/worker/sdk-py). - **Web and Node.js apps**: the [TypeScript SDK](https://docs.allora.network/consume/sdk-ts) is the lightest client and includes BTC/ETH price prediction helpers; like the Python client, it returns inferences with an EVM-verifiable signature. - **Backend services and infrastructure** (indexers, exchanges, monitoring): the [Go SDK](https://docs.allora.network/consume/sdk-go) pools gRPC/REST/CometBFT endpoints with load balancing and failover, and includes wallet and transaction helpers. - **Python apps** that only read data: the [Python SDK](https://docs.allora.network/consume/sdk-py)'s `AlloraAPIClient` and `AlloraRPCClient` cover the Allora API and typed chain queries without running a worker. No SDK in your language? The [Allora API](https://docs.allora.network/consume/api) and [RPC endpoints](https://docs.allora.network/consume/rpc-grpc) work from any HTTP or gRPC client. --- # Allora TypeScript SDK Source: https://docs.allora.network/consume/sdk-ts Fetch Allora topics, network inferences, and signed price predictions from JavaScript and TypeScript applications. The Allora TypeScript SDK ([`@alloralabs/allora-sdk`](https://www.npmjs.com/package/@alloralabs/allora-sdk)) is a lightweight client for the Allora API. Use it to browse topics, read the latest network inference for any topic, and fetch signed price predictions ready for on-chain (EVM) consumption. It works in Node.js 18+ and anywhere else `fetch` is available. ## Goal Fetch a signed BTC price prediction, list the network's topics, and read the latest network inference for a specific topic. ## Prerequisites - Node.js 18 or newer - An Allora API key — get one for free at [developer.allora.network](https://developer.allora.network) ## Steps ### 1. Install the SDK ```bash # Using npm npm install @alloralabs/allora-sdk # Using yarn yarn add @alloralabs/allora-sdk ``` Import from the package root: `from '@alloralabs/allora-sdk'`. The `@alloralabs/allora-sdk/v2` subpath used by older examples no longer resolves as of v0.1.1 and fails with `ERR_PACKAGE_PATH_NOT_EXPORTED`. ### 2. Fetch a signed price prediction Save this as `price.ts`: ```typescript import { AlloraAPIClient, ChainSlug, PriceInferenceToken, PriceInferenceTimeframe, } from "@alloralabs/allora-sdk"; const client = new AlloraAPIClient({ chainSlug: ChainSlug.TESTNET, apiKey: process.env.ALLORA_API_KEY, }); async function main() { const inference = await client.getPriceInference( PriceInferenceToken.BTC, PriceInferenceTimeframe.EIGHT_HOURS, ); console.log(`BTC price prediction (8h): ${inference.inference_data.network_inference_normalized}`); console.log(`Signature: ${inference.signature}`); } main(); ``` ### 3. Run it ```bash export ALLORA_API_KEY="" npx tsx price.ts ``` Expected output (values will differ): ``` BTC price prediction (8h): 63336.29812746 Signature: 0x4c7c574aff854cae2cd89810b48a3427d6c6c0c392a5a86ff71a0a2be9a0714f72236d8cdea687a29aa262ed540d19a52be50ba33a577ccdffa75654695e0d131b ``` `network_inference_normalized` is the decimal-adjusted prediction; `network_inference` is the raw fixed-point value. The `signature` covers the inference payload in the requested `SignatureFormat`, so a smart contract can verify the data on-chain. ## Verify - The script prints a plausible BTC price and a `0x…` signature. - Cross-check the value against the corresponding topic on the [testnet explorer](https://testnet.explorer.allora.network). ## List all topics ```typescript import { AlloraAPIClient, ChainSlug, AlloraTopic } from "@alloralabs/allora-sdk"; const client = new AlloraAPIClient({ chainSlug: ChainSlug.TESTNET, apiKey: process.env.ALLORA_API_KEY, }); async function main() { const topics: AlloraTopic[] = await client.getAllTopics(); console.log(`Found ${topics.length} topics`); for (const topic of topics.filter((t) => t.is_active).slice(0, 5)) { console.log(`- [${topic.topic_id}] ${topic.topic_name} (workers: ${topic.worker_count})`); } } main(); ``` Output: ``` Found 73 topics - [42] BTC/USD - 8h Price Prediction (workers: 12) - [37] SOL/USD - 5min Price Prediction (workers: 3) - [38] SOL/USD - 8h Price Prediction (workers: 17) - [41] ETH/USD - 8h Price Prediction (workers: 16) - [64] 8h BTC/USD Log-Return Prediction (5min Updates) (workers: 2) ``` ## Read the inference for any topic Any topic ID from `getAllTopics()` works — not just the price prediction topics: ```typescript import { AlloraAPIClient, ChainSlug } from "@alloralabs/allora-sdk"; const client = new AlloraAPIClient({ chainSlug: ChainSlug.TESTNET, apiKey: process.env.ALLORA_API_KEY, }); async function main() { // Topic 42 is the BTC/USD 8-hour price prediction topic on testnet const inference = await client.getInferenceByTopicID(42); console.log(`Network inference: ${inference.inference_data.network_inference_normalized}`); console.log(`Topic ID: ${inference.inference_data.topic_id}`); console.log(`Timestamp: ${inference.inference_data.timestamp}`); } main(); ``` Output: ``` Network inference: 64665.180764847867167991 Topic ID: 42 Timestamp: 1785448685 ``` ## API reference ### `AlloraAPIClient` ```typescript constructor(config: AlloraAPIClientConfig) ``` - `chainSlug` — `ChainSlug.TESTNET` or `ChainSlug.MAINNET`. Selects which chain's topics are queried. Defaults to mainnet when omitted. - `apiKey` — your API key. If omitted, a shared default key is used, which may be rate limited; always set your own key in production. - `baseAPIUrl` — optional API base URL. Defaults to `https://api.upshot.xyz/v2`; `https://api.allora.network/v2` serves the same API and also works here. #### `getAllTopics()` ```typescript async getAllTopics(): Promise ``` Fetches every topic on the selected chain, following pagination automatically. #### `getInferenceByTopicID(topicID, signatureFormat?)` ```typescript async getInferenceByTopicID( topicID: number, signatureFormat: SignatureFormat = SignatureFormat.ETHEREUM_SEPOLIA ): Promise ``` Fetches the latest network inference for a topic, signed in the requested format. #### `getPriceInference(asset, timeframe, signatureFormat?)` ```typescript async getPriceInference( asset: PriceInferenceToken, timeframe: PriceInferenceTimeframe, signatureFormat: SignatureFormat = SignatureFormat.ETHEREUM_SEPOLIA ): Promise ``` Fetches the latest price prediction for an asset/timeframe pair — a convenience wrapper over the corresponding price topic. ### Enums ```typescript enum ChainSlug { TESTNET = "testnet", MAINNET = "mainnet", } enum ChainID { TESTNET = "allora-testnet-1", MAINNET = "allora-mainnet-1", } enum PriceInferenceToken { BTC = "BTC", ETH = "ETH", } enum PriceInferenceTimeframe { FIVE_MIN = "5m", EIGHT_HOURS = "8h", } enum SignatureFormat { ETHEREUM_SEPOLIA = "ethereum-11155111", } ``` ### Interfaces ```typescript interface AlloraAPIClientConfig { chainSlug?: ChainSlug; apiKey?: string; baseAPIUrl?: string; } interface AlloraTopic { topic_id: number; topic_name: string; description?: string | null; epoch_length: number; ground_truth_lag: number; loss_method: string; worker_submission_window: number; worker_count: number; reputer_count: number; total_staked_allo: number; total_emissions_allo: number; is_active: boolean | null; updated_at: string; } interface AlloraInferenceData { network_inference: string; network_inference_normalized: string; confidence_interval_percentiles: string[]; confidence_interval_percentiles_normalized: string[]; confidence_interval_values: string[]; confidence_interval_values_normalized: string[]; topic_id: string; timestamp: number; extra_data: string; } interface AlloraInference { signature: string; inference_data: AlloraInferenceData; } ``` The `confidence_interval_*` fields are declared on `AlloraInferenceData` but the consumer endpoints do not currently populate them — guard against `undefined` before using them. Responses additionally carry a `token_decimals` field that is not yet part of the declared type. ## Troubleshoot - **`ERR_PACKAGE_PATH_NOT_EXPORTED: Package subpath './v2' is not defined`** — you are importing from `@alloralabs/allora-sdk/v2`. Since v0.1.1 the client is exported from the package root: `import { AlloraAPIClient } from '@alloralabs/allora-sdk'`. - **`fetch is not defined`** — the SDK relies on the global `fetch` API; upgrade to Node.js 18+. - **HTTP 401/403 errors** — check that `ALLORA_API_KEY` is set and valid. Free keys are available at [developer.allora.network](https://developer.allora.network). - **HTTP 429 (rate limited)** — you are on the shared default key or exceeding your key's limits; pass your own `apiKey` and add retry with backoff. - **Empty or missing fields on the inference** — see the Callout above: only `network_inference`, `network_inference_normalized`, `topic_id`, `timestamp`, and `extra_data` are currently returned in `inference_data`. ## Next - Compare SDKs and pick a language: [SDKs overview](https://docs.allora.network/consume/sdk-overview) - Understand the underlying REST endpoints: [Allora API](https://docs.allora.network/consume/api) - Consume from Python or Go: [Python SDK](https://docs.allora.network/consume/sdk-py), [Go SDK](https://docs.allora.network/consume/sdk-go) - Build and submit predictions instead: [worker guide (Python SDK)](https://docs.allora.network/build/worker/sdk-py) --- # Allora Python SDK Source: https://docs.allora.network/consume/sdk-py Submit ML predictions with AlloraWorker, make typed chain queries with AlloraRPCClient, and read topics and inferences with AlloraAPIClient. The Allora Python SDK ([`allora_sdk`](https://pypi.org/project/allora-sdk/)) lets you submit machine learning predictions, query blockchain data, and access network inference results. It is organized in three layers: | Layer | Class | Use it to | | :--- | :--- | :--- | | Worker | `AlloraWorker` | Submit your ML model's predictions to Allora topics. Handles wallet creation, registration, transactions, and retries so you can focus on model engineering. | | RPC client | `AlloraRPCClient` | Make typed queries and send transactions directly to the Allora chain over gRPC or REST, and subscribe to chain events over WebSocket. | | API client | `AlloraAPIClient` | Read topics and network inference results over HTTPS from the Allora API. No wallet required. | ## Goal Run a minimal inference worker that submits predictions to Allora's testnet sandbox topic (topic ID 69), then use the RPC and API clients to read data back from the network. ## Prerequisites - Python 3.10–3.13 - An Allora API key — get one for free at [developer.allora.network](https://developer.allora.network). On testnet, the worker uses it to automatically request ALLO gas from the faucet. ## Steps ### 1. Install the SDK ```bash pip install allora_sdk ``` This also installs the SDK's [command-line tools](#command-line-tools). ### 2. Write the worker Save this as `worker.py`, replacing the body of `run_model` with your model's prediction logic: ```python import asyncio import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, RunContext async def run_model(ctx: RunContext) -> float: # Your ML model's prediction logic goes here return 123.45 async def main(): worker = AlloraWorker.inferer( run=run_model, topic_id=69, network=AlloraNetworkConfig.testnet(), api_key=os.environ["ALLORA_API_KEY"], ) async for result in worker.run(): if isinstance(result, Exception): print(f"Inference worker error: {result}") else: print(f"Prediction submitted to Allora: {result.submission}") asyncio.run(main()) ``` In a Jupyter or Colab notebook, an event loop is already running: call `await main()` instead of `asyncio.run(main())`. ### 3. Run it ```bash export ALLORA_API_KEY="" python worker.py ``` On the first run, the worker walks you through network onboarding automatically: - It connects to Allora's **testnet**, where no real funds are exchanged. - It asks for a wallet mnemonic — press **Enter** to have one generated for you. Your identity (an `allo...` address) is saved to a `.allora_key` file in the working directory and reused on later runs. - If the wallet's balance is low, it requests a small amount of ALLO — the network's gas currency — from the testnet faucet, using your API key. - It registers the worker on [Allora's sandbox topic (ID 69)](https://testnet.explorer.allora.network/topics/69), a topic for newcomers to verify their setup. **There are no penalties for submitting inaccurate inferences to this topic.** The worker then listens for the topic's submission windows and calls your `run_model` function each time one opens, submitting the returned value on-chain. Press Ctrl-C once for a graceful shutdown. ### Advanced configuration `AlloraWorker.inferer()` accepts more options when you need finer control: ```python import os from allora_sdk import AlloraNetworkConfig, AlloraWorker, FeeTier, RunContext from allora_sdk.rpc_client.config import AlloraWalletConfig def my_model(ctx: RunContext) -> float: # Your ML model's prediction logic goes here return 123.45 worker = AlloraWorker.inferer( # Prediction function: sync or async, returning a float or str run=my_model, # Bring your own wallet instead of the auto-generated `.allora_key` identity wallet=AlloraWalletConfig(mnemonic=os.environ["ALLORA_WALLET_MNEMONIC"]), # Network helpers: AlloraNetworkConfig.testnet(), .mainnet(), .local() -- # or specify the options directly: network=AlloraNetworkConfig( chain_id="allora-testnet-1", url="grpc+https://allora-grpc.testnet.allora.network:443", websocket_url="wss://allora-rpc.testnet.allora.network/websocket", fee_denom="uallo", ), # Topic to submit predictions to topic_id=69, # Used to fetch ALLO for gas fees from the faucet on testnet api_key=os.environ["ALLORA_API_KEY"], # How much to pay to prioritize inclusion within an epoch: # FeeTier.ECO, FeeTier.STANDARD (default), or FeeTier.PRIORITY fee_tier=FeeTier.PRIORITY, # Seconds between polls for open submission windows (default 120) polling_interval=120, # Verbose logging debug=True, ) ``` ## Verify - Your terminal should log the worker's wallet address and balance, then print `Prediction submitted to Allora: ...` each time a submission window for the topic opens. - Open [testnet.explorer.allora.network/topics/69](https://testnet.explorer.allora.network/topics/69) and look for your worker's `allo...` address among the topic's workers. ## AlloraRPCClient: typed chain queries and transactions `AlloraRPCClient` is the low-level blockchain client the worker is built on. It exposes typed query clients for the chain's modules (`emissions`, `mint`, `auth`, `bank`, `tendermint`, `tx`), transaction submission with fee estimation and signing, and WebSocket event subscriptions via `client.events`. The wire protocol is chosen by the URL scheme in the network config: `grpc+http(s)://` uses gRPC, `rest+http(s)://` uses the Cosmos-LCD REST API. ### Initialize ```python import os from allora_sdk import AlloraRPCClient from allora_sdk.rpc_client.config import AlloraWalletConfig # Presets for common networks client = AlloraRPCClient.testnet() # client = AlloraRPCClient.mainnet() # client = AlloraRPCClient.local() # A wallet is only needed to send transactions -- queries work without one client = AlloraRPCClient.testnet( wallet=AlloraWalletConfig(mnemonic=os.environ["ALLORA_WALLET_MNEMONIC"]), ) # Or configure entirely from environment variables: # CHAIN_ID, RPC_ENDPOINT, WEBSOCKET_ENDPOINT, FAUCET_URL, FEE_DENOM, # FEE_MIN_GAS_PRICE, and PRIVATE_KEY / MNEMONIC / MNEMONIC_FILE / ADDRESS_PREFIX client = AlloraRPCClient.from_env() ``` ### Query the chain Queries take typed protobuf request objects and return typed responses: ```python import asyncio from allora_sdk import AlloraRPCClient from allora_sdk.rpc_client.protos.cosmos.base.tendermint.v1beta1 import GetLatestBlockRequest async def main(): client = AlloraRPCClient.testnet() response = await client.tendermint.query.get_latest_block(GetLatestBlockRequest()) print(f"Current block height: {response.sdk_block.header.height}") asyncio.run(main()) ``` Allora-specific queries live under `client.emissions.query` (topics, registrations, nonces, network inferences), with matching request/response types in the SDK's `rpc_client.protos` modules. When a wallet is configured, `client.emissions.tx` submits transactions such as worker registration (`register`) and inference submission (`insert_worker_payload`) — these are the same calls `AlloraWorker` makes for you. ## AlloraAPIClient: topics and inferences over REST `AlloraAPIClient` is a slim, fully asynchronous HTTP client for the Allora API (`https://api.allora.network/v2`). Use it to browse all topics and their metadata and to fetch the latest network inference for a topic — including the price prediction topics (BTC, ETH, and more across multiple timeframes) — without touching the chain directly. You will need an Allora API key: get one for free at [developer.allora.network](https://developer.allora.network). ```python import asyncio import os from allora_sdk.api_client import AlloraAPIClient, ChainID client = AlloraAPIClient(api_key=os.environ["ALLORA_API_KEY"]) async def main(): # List every topic on the network (pagination is handled automatically) topics = await client.get_all_topics() print(f"Found {len(topics)} topics") # Latest network inference for a topic (13 is an ETH price prediction topic) inference = await client.get_inference_by_topic_id(13) print(f"Latest network inference: {inference.inference_data.network_inference_normalized}") asyncio.run(main()) ``` - `get_all_topics()` returns a list of `Topic` models with fields such as `topic_id`, `topic_name`, `description`, `epoch_length`, `loss_method`, `worker_count`, `reputer_count`, and `is_active`. - `get_inference_by_topic_id(topic_id)` returns an `Inference` model whose `inference_data` includes the raw `network_inference` and the decimal-adjusted `network_inference_normalized`. - The client defaults to testnet topics; pass `chain_id=ChainID.MAINNET` (imported above) to read mainnet topics. ## Command-line tools Installing `allora_sdk` also puts two utilities on your `PATH`: - **`allora-export-txs`** — exports a worker's inference transactions to a CSV file: ```bash allora-export-txs --address --output_file transactions.csv ``` - **`allora-topic-lifecycle-visualizer`** — given a log file produced by `AlloraWorker`, plots the phases of a topic's lifecycle over the logged block range: ```bash allora-topic-lifecycle-visualizer --log_file worker.log ``` Run either tool with `-h` for all options. ## Troubleshoot - **`RuntimeError: asyncio.run() cannot be called from a running event loop`** — you are in a notebook (Jupyter/Colab), where an event loop is already running. Replace `asyncio.run(main())` with `await main()`. - **Worker prompts `Mnemonic:` on startup** — no wallet was configured and no `.allora_key` file exists yet. Press Enter to generate a fresh identity, or paste an existing mnemonic. Back up the resulting `.allora_key` file; delete it to start over with a new identity. - **`Too many faucet requests`** — the testnet faucet is rate-limited. Send ALLO to your worker's address from another wallet, or request funds manually at [faucet.testnet.allora.network](https://faucet.testnet.allora.network). - **gRPC `StatusCode.UNIMPLEMENTED` with `unknown service emissions.vN.QueryService`** — the network has been upgraded to a newer protobuf revision than the one bundled with your installed SDK release. Upgrade with `pip install --upgrade allora_sdk`; if the newest release still fails, the deployed network is ahead of the latest SDK release — check the [SDK issue tracker](https://github.com/allora-network/allora-sdk-py/issues). - **HTTP errors from `api.allora.network`** — check that your API key is set and valid. Free keys are available at [developer.allora.network](https://developer.allora.network). ## Next - Find a topic to predict on: [existing topics](https://docs.allora.network/build/forge/topics) - Productionize your worker: [deploy a worker with Docker](https://docs.allora.network/build/worker/containerize) - Consume inferences from your app: [Allora API endpoint](https://docs.allora.network/consume/api), the [TypeScript SDK](https://docs.allora.network/consume/sdk-ts), or the [Go SDK](https://docs.allora.network/consume/sdk-go) - Train and deploy a model end to end with the [Forge Builder Kit](https://github.com/allora-network/allora-forge-builder-kit) --- # Allora Go SDK Source: https://docs.allora.network/consume/sdk-go Read topics, inferences, and market data over the Allora API, and make typed chain queries with load balancing and failover, from Go. The Allora Go SDK ([`allora-sdk-go`](https://github.com/allora-network/allora-sdk-go)) is built for backend services and infrastructure that consume Allora data at scale. It provides two clients: | Client | Constructor | Use it to | | :--- | :--- | :--- | | API client | `allora.NewAPIClient` | Read topics, latest network inferences, and historical OHLC market data over HTTPS from the Allora API. | | Chain client | `allora.NewClient` | Make typed queries against the Allora chain's modules (emissions, mint, auth, bank, staking, and more) over gRPC, REST, or CometBFT RPC — with round-robin load balancing, automatic failover, and WebSocket event subscriptions. | The chain client also ships wallet and transaction helpers (`GenerateWallet`, `NewWalletFromMnemonic`, `CreateSignedSendTx`) aimed at exchanges and custodial integrations. ## Goal Read a topic and its latest network inference through the Allora API, then query the chain directly and subscribe to new blocks. ## Prerequisites - Go 1.24 or newer - An Allora API key — get one for free at [developer.allora.network](https://developer.allora.network) ## Steps ### 1. Install the SDK Inside a Go module (`go mod init ` if you are starting fresh): ```bash go get github.com/allora-network/allora-sdk-go ``` ### 2. Read topics and inferences with the API client Save this as `main.go`: ```go package main import ( "fmt" "os" allora "github.com/allora-network/allora-sdk-go" ) func main() { client := allora.NewAPIClient(os.Getenv("ALLORA_API_KEY")) // Fetch a single topic (42 is the BTC/USD 8-hour price prediction topic) topic, err := client.GetTopic(42) if err != nil { fmt.Fprintln(os.Stderr, "failed to fetch topic:", err) os.Exit(1) } fmt.Printf("Topic %d: %s (workers: %d, active: %v)\n", topic.TopicID, topic.TopicName, topic.WorkerCount, topic.IsActive) if topic.LatestNetworkInference != nil { fmt.Printf("Latest network inference: %s\n", topic.LatestNetworkInference.CombinedValue) } // Iterate over every topic on the network (pagination is handled for you) count := 0 for t, err := range client.GetTopics() { if err != nil { fmt.Fprintln(os.Stderr, "failed to fetch topics:", err) os.Exit(1) } if t.IsActive { count++ } } fmt.Printf("Active topics: %d\n", count) } ``` ### 3. Run it ```bash export ALLORA_API_KEY="" go run . ``` Expected output (values will differ): ``` Topic 42: BTC/USD - 8h Price Prediction (workers: 12, active: true) Latest network inference: 64757.14233536308300576439034902826 Active topics: 33 ``` The API client talks to `https://api.allora.network/v2` and currently reads the **testnet** (`allora-testnet-1`) topic list. Each `Topic` includes metadata (epoch length, worker and reputer counts, stake) plus `LatestNetworkInference` with the topic's combined value and timestamp. ## Verify - The program prints the topic name, a numeric `Latest network inference`, and a non-zero active-topic count. - Cross-check the inference value against the topic page on the [testnet explorer](https://testnet.explorer.allora.network/topics/42). ## Query the chain directly `allora.NewClient` pools any mix of gRPC, Cosmos-REST, and CometBFT RPC endpoints, load-balances requests across them, and fails over automatically. Query methods take the typed protobuf request objects from [`allora-chain`](https://github.com/allora-network/allora-chain) and Cosmos SDK modules: ```go package main import ( "context" "fmt" "os" "time" emissionstypes "github.com/allora-network/allora-chain/x/emissions/types" allora "github.com/allora-network/allora-sdk-go" "github.com/allora-network/allora-sdk-go/config" cmtservice "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" "github.com/rs/zerolog" ) func main() { logger := zerolog.New(os.Stderr).Level(zerolog.WarnLevel) cfg := &config.ClientConfig{ Endpoints: []config.EndpointConfig{ { URL: "allora-grpc.testnet.allora.network:443", Protocol: config.ProtocolGRPC, }, { URL: "https://allora-api.testnet.allora.network", Protocol: config.ProtocolREST, }, }, RequestTimeout: 30 * time.Second, ConnectionTimeout: 10 * time.Second, } client, err := allora.NewClient(cfg, logger) if err != nil { logger.Fatal().Err(err).Msg("failed to create client") } defer client.Close() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // Latest block height block, err := client.Cosmos().Tendermint().GetLatestBlock(ctx, &cmtservice.GetLatestBlockRequest{}) if err != nil { logger.Fatal().Err(err).Msg("failed to get latest block") } fmt.Printf("Latest block height: %d\n", block.SdkBlock.Header.Height) // Topic metadata from the emissions module topic, err := client.Cosmos().Emissions().GetTopic(ctx, &emissionstypes.GetTopicRequest{TopicId: 42}) if err != nil { logger.Fatal().Err(err).Msg("failed to get topic") } fmt.Printf("Topic 42: %q (epoch length: %d blocks)\n", topic.Topic.Metadata, topic.Topic.EpochLength) // Latest network inference for the topic resp, err := client.Cosmos().Emissions().GetLatestNetworkInferences(ctx, &emissionstypes.GetLatestNetworkInferencesRequest{TopicId: 42}) if err != nil { logger.Fatal().Err(err).Msg("failed to get network inferences") } fmt.Printf("Inference block height: %d\n", resp.InferenceBlockHeight) for _, v := range resp.NetworkInferences.CombinedValue { fmt.Printf("Combined value (label %q): %s\n", v.LabelName, v.Value.String()) } } ``` Output: ``` Latest block height: 10297833 Topic 42: "BTC/USD - 8h Price Prediction" (epoch length: 35 blocks) Inference block height: 10297796 Combined value (label "y"): 64757.14233536308300576439034902826 ``` - `client.Cosmos()` exposes typed query clients per module: `Emissions()` (100+ queries), `Mint()`, `Auth()`, `Bank()`, `Staking()`, `Tendermint()`, and more. Endpoint URLs and the current emissions version per network are listed in [Networks](https://docs.allora.network/reference/networks). - Network inference values are **labeled**: single-output topics carry the canonical label `y`; multi-output topics return one entry per label. See the [Allora API page](https://docs.allora.network/consume/api) for what each field of the inference bundle means. - To query at a historical height, pass the `config.Height` call option: `client.Cosmos().Emissions().GetTopic(ctx, req, config.Height(5601386))`. ## Subscribe to chain events Add a CometBFT RPC endpoint with a `WebsocketURL` and the client can stream chain events — for example, to react the moment a new block (and any inference in it) lands: ```go package main import ( "context" "fmt" "os" "time" ctypes "github.com/cometbft/cometbft/types" "github.com/rs/zerolog" allora "github.com/allora-network/allora-sdk-go" "github.com/allora-network/allora-sdk-go/config" "github.com/allora-network/allora-sdk-go/tmrpc" ) func main() { logger := zerolog.New(os.Stderr).Level(zerolog.WarnLevel) cfg := &config.ClientConfig{ Endpoints: []config.EndpointConfig{ { URL: "https://allora-rpc.testnet.allora.network", WebsocketURL: "https://allora-rpc.testnet.allora.network/websocket", Protocol: config.ProtocolTendermintRPC, }, }, } client, err := allora.NewClient(cfg, logger) if err != nil { logger.Fatal().Err(err).Msg("failed to create client") } defer client.Close() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // The CometBFT RPC pool serves raw block data block, err := client.Tendermint().Block(ctx, nil) if err != nil { logger.Fatal().Err(err).Msg("failed to get latest block") } fmt.Printf("Starting from block %d\n", block.Block.Header.Height) // Subscribe to new blocks (any CometBFT event query works here) mailbox := tmrpc.NewMailbox(100) client.Subscribe(mailbox, "tm.event='NewBlock'") for i := 0; i < 2; i++ { select { case <-mailbox.Notify(): event, ok := mailbox.Retrieve() if !ok { continue } if blockEvent, ok := event.(ctypes.EventDataNewBlock); ok { fmt.Printf("New block: height %d with %d txs\n", blockEvent.Block.Height, len(blockEvent.Block.Txs)) } case <-time.After(30 * time.Second): logger.Fatal().Msg("timed out waiting for a block") } } } ``` Output: ``` Starting from block 10297841 New block: height 10297842 with 5 txs New block: height 10297843 with 1 txs ``` ## Fetch historical market data (OHLC) The API client can also page through OHLC candles for building or evaluating price models: ```go package main import ( "context" "fmt" "os" "time" allora "github.com/allora-network/allora-sdk-go" ) func main() { client := allora.NewAPIClient(os.Getenv("ALLORA_API_KEY")) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // Pages of BTC/USD candles since the given date; stop after the first page fromDate := time.Now().UTC().Format("2006-01-02") for page, err := range client.GetOHLCData(ctx, "btcusd", fromDate) { if err != nil { fmt.Fprintln(os.Stderr, "failed to fetch OHLC data:", err) os.Exit(1) } for _, bar := range page.Data[:3] { fmt.Printf("%s %s [%s] open=%s high=%s low=%s close=%s\n", bar.Ticker, bar.Date, bar.ExchangeCode, bar.Open, bar.High, bar.Low, bar.Close) } break } } ``` Output: ``` btcusd 2026-07-30T22:09:00.000Z [TIINGO] open=64878.378628357044 high=64892.65615754596 low=64846.04535529084 close=64889.57305797366 btcusd 2026-07-30T22:08:00.000Z [TIINGO] open=64821.23928651763 high=64904.40521717826 low=64813.484881886034 close=64881.548589323946 btcusd 2026-07-30T22:07:00.000Z [TIINGO] open=64806.466592959274 high=64828.34495431894 low=64789.91922168581 close=64822.13862462402 ``` Tickers are lowercase pairs such as `btcusd`, and `fromDate` is a `YYYY-MM-DD` string. Both `GetTopics()` and `GetOHLCData()` return Go 1.23+ iterators (`iter.Seq2`) that follow the API's continuation tokens automatically. ## API client reference ```go func NewAPIClient(apiKey string, opts ...APIClientOption) *apiClient ``` If `apiKey` is empty, a shared default key is used, which may be rate limited — always pass your own key in production. Options: `WithTimeout(d)`, `WithBackoff(baseDelay, maxDelay, jitter)`, `WithDefaultBackoff()`, `WithLogger(logger)`, `WithMetrics()`. | Method | Returns | Description | | :--- | :--- | :--- | | `GetTopics()` | `iter.Seq2[*Topic, error]` | Iterates every topic, following pagination automatically. | | `GetTopic(topicID uint64)` | `(*Topic, error)` | One topic, including `LatestNetworkInference` (`CombinedValue`, `NaiveValue`, `Timestamp`). | | `GetOHLCData(ctx, ticker, fromDate)` | `iter.Seq2[*OHLCResponse, error]` | Pages of OHLC candles for a ticker since `fromDate`. | ## Troubleshoot - **`at least one endpoint must be specified` / `failed to create any valid clients`** — the chain client requires at least one endpoint with a `URL` and a valid `Protocol` (`config.ProtocolGRPC`, `config.ProtocolREST`, or `config.ProtocolTendermintRPC`). A `WebsocketURL` alone is not enough. - **`error closing active client: not started` logged on shutdown** — a harmless log line emitted by `client.Close()` when a CometBFT RPC endpoint was configured but only its WebSocket was used. - **gRPC `Unimplemented` errors mentioning an emissions `QueryService` version** — the deployed network runs a different emissions protobuf revision than your SDK release (the SDK currently targets emissions v10 on testnet). Upgrade with `go get -u github.com/allora-network/allora-sdk-go` — and see [Networks](https://docs.allora.network/reference/networks) for the version deployed per network. - **HTTP 401/429 from `api.allora.network`** — check that `ALLORA_API_KEY` is set and valid; free keys are available at [developer.allora.network](https://developer.allora.network). On 429, back off and retry (`WithDefaultBackoff()` handles this for you). ## Next - Compare SDKs and pick a language: [SDKs overview](https://docs.allora.network/consume/sdk-overview) - Understand the inference bundle you are reading: [Allora API](https://docs.allora.network/consume/api) - Query without an SDK: [RPC data access](https://docs.allora.network/consume/rpc-grpc) - Build and submit predictions instead: [worker guide (Python SDK)](https://docs.allora.network/build/worker/sdk-py) --- # Accessing Allora Data Through RPC Source: https://docs.allora.network/consume/rpc-grpc In addition to the Allora API, you can also access Allora network data directly through RPC (Remote Procedure Call) endpoints. In addition to the [Allora API](https://docs.allora.network/consume/api), you can also access Allora network data directly through RPC (Remote Procedure Call) endpoints. This provides an alternative method for consuming outputs from the network, especially useful for applications that need to interact directly with the blockchain. ## Prerequisites - [`allorad` CLI](https://docs.allora.network/get-started/cli) installed, for the command-line examples - Access to an Allora node: the CometBFT RPC endpoint for `allorad`, or the LCD (REST) endpoint for the programmatic examples — see [Networks](https://docs.allora.network/reference/networks) For a complete list of available RPC endpoints and commands, see the [allorad reference section](https://docs.allora.network/reference/allorad). ## RPC URL and Chain ID Each network uses a different RPC URL and Chain ID which are needed to specify which network to run commands on when using specific commands on allorad. ### Testnet - **RPC URL** (CometBFT): `https://allora-rpc.testnet.allora.network/` - **LCD URL** (Cosmos SDK REST): `https://allora-api.testnet.allora.network/` - **Chain ID**: `allora-testnet-1` See [Networks](https://docs.allora.network/reference/networks) for the current endpoints of every network, including the versioned `emissions` namespace each one serves. ## RPC Endpoints for Consumers The following RPC methods are particularly useful for consumers looking to access inference data from the Allora network: ### Get Latest Network Inferences This is the primary method for consumers to retrieve the latest network inference for a specific topic. ```bash allorad q emissions latest-network-inferences [topic_id] --node ``` **Parameters:** - `topic_id`: The identifier of the topic for which you want to retrieve the latest network inference. - `RPC_URL`: The URL of the RPC node you're connecting to. **Example:** ```bash allorad q emissions latest-network-inferences 1 --node https://allora-rpc.testnet.allora.network/ ``` An **outlier-resistant** variant (single-label regression topics only) is available via `allorad q emissions latest-network-inferences-outlier-resistant [topic_id]`. **Response:** The response includes the network inference bundle — the combined value, individual worker values, a naive baseline, and one-out/one-in values. Since v0.17.0 every value is **labeled**; single-output topics use the canonical label `y`. Here's a simplified example: ```json { "network_inferences": { "topic_id": "1", "nonce": "1349577", "combined_value": [ { "label_id": 1, "label_name": "y", "value": "2605.533879185080648394998043723508" } ], "inferer_values": [ { "worker": "allo102ksu3kx57w0mrhkg37kvymmk2lgxqcan6u7yn", "values": [ { "label_id": 1, "label_name": "y", "value": "2611.01109296" } ] }, { "worker": "allo10q6hm2yae8slpvvgmxqrcasa30gu5qfysp4wkz", "values": [ { "label_id": 1, "label_name": "y", "value": "2661.505295679922" } ] } ], "naive_value": [ { "label_id": 1, "label_name": "y", "value": "2605.533879185080648394998043723508" } ] }, "inference_block_height": "1349577" } ``` The `combined_value` field is a list of labeled values representing the optimized inference that takes both worker submissions and forecast data into account. For a single-output topic it holds a single entry (labeled `y`), which is typically the value you want for most consumer applications. A multi-output / classification topic returns one entry per label. ## Using RPC in Your Applications The CometBFT `abci_query` method takes **protobuf-encoded** request bytes and returns protobuf-encoded response bytes — it does not accept or return JSON. Calling it from a plain HTTP client therefore requires generated protobuf stubs for the emissions module. For everything below, the Cosmos SDK **LCD (REST)** endpoints expose the same queries as JSON over `GET`, which is what a typical application should use. Every `allorad q emissions` query has a matching LCD path. The one used below is `//latest_network_inferences/{topic_id}`, where the namespace is `emissions/v10` on testnet and `emissions/v9` on mainnet. ### JavaScript/TypeScript Example ```typescript // See https://docs.allora.network/reference/networks for the LCD URL and // emissions namespace of each network. const LCD_URL = "https://allora-api.testnet.allora.network"; const EMISSIONS = "emissions/v10"; async function getLatestInference(topicId: number): Promise { const url = `${LCD_URL}/${EMISSIONS}/latest_network_inferences/${topicId}`; const response = await fetch(url); if (!response.ok) { throw new Error(`LCD request failed: ${response.status} ${response.statusText}`); } return response.json(); } async function main() { const data = await getLatestInference(1); // combined_value is a list of labeled values; a single-output topic has one entry ("y") console.log(`Latest inference: ${data.network_inferences.combined_value[0].value}`); console.log(`Inference block height: ${data.inference_block_height}`); } main().catch((err) => { console.error(err); process.exit(1); }); ``` ### Python Example ```python import json import urllib.request # See https://docs.allora.network/reference/networks for the LCD URL and # emissions namespace of each network. LCD_URL = "https://allora-api.testnet.allora.network" EMISSIONS = "emissions/v10" def get_latest_inference(topic_id): url = f"{LCD_URL}/{EMISSIONS}/latest_network_inferences/{topic_id}" with urllib.request.urlopen(url, timeout=30) as response: return json.load(response) data = get_latest_inference(1) # combined_value is a list of labeled values; a single-output topic has one entry ("y") print(f"Latest inference: {data['network_inferences']['combined_value'][0]['value']}") print(f"Inference block height: {data['inference_block_height']}") ``` ## RPC vs API: When to Use Each ### Use RPC When: - You need direct blockchain access without intermediaries - You want to query historical data that might not be available through the API - You're building applications that need to interact with multiple aspects of the Allora network - You want to avoid potential rate limiting on the API ### Use the API When: - You need a simpler interface with standardized authentication - You want to avoid the complexity of RPC calls - You're primarily interested in the latest inference data - You need additional features provided by the API that aren't available through RPC RPC nodes may have their own rate limiting or access restrictions. Make sure to implement proper error handling and retry logic in your applications. --- # Validators Source: https://docs.allora.network/operate/validators Validators maintain the security and integrity of the Allora appchain. Validators maintain the security and integrity of the Allora appchain. ## What do Validators do? ### Secure Chain with Stake Validators secure the Allora appchain by staking tokens in a delegated proof of stake system through CometBFT. The more a validator stakes, the greater their influence on the overall security and consensus of the blockchain. Similarly, stakeholders can delegate their tokens to validators, further enhancing the security and reliability of the chain. #### Topic Security vs Chain Security - *Topic security* is a subset of *chain security*. - If the underlying state is corrupted, topic security is compromised. - One can have chain security without topic security if: - Validators are generally honest (weighted by stake). - Reputers of a specific topic are generally dishonest (weighted by stake). ### Validate Transactions Validators validate transactions and blocks, ensuring that all transactions are legitimate and conform to the rules of the blockchain ### Participate in Consensus Validators participate in the consensus mechanism of the appchain, running CometBFT. By participating in the consensus, validators collectively agree on the state of the blockchain. ### Receive Rewards Validators [receive rewards](https://docs.allora.network/learn/consensus-and-rewards) based on the amount of stake they hold or have delegated to them. ## Learn More Test run a validator of the Allora appchain by following the instructions [here](https://docs.allora.network/operate/validators/run-full-node). CometBFT can be explored in the following two articles, among many other places: - [Staking and Delegation in Cosmos](https://medium.com/@notional-ventures/staking-and-delegation-in-cosmos-db660154bcf9) - [CometBFT: Security and Consensus in Cosmos](https://medium.com/@notional-ventures/cometbft-security-and-consensus-in-cosmos-part-1-a7be84f0bf25) --- # System Requirements Source: https://docs.allora.network/operate/validators/nop-requirements You can use any modern Linux distribution (internally we use Debian 12 x86_64) to run an Allora validator. You can use any modern Linux distribution to run an Allora validator. Internally we use **Debian 12** x86_64. ## MAINNET and TESTNET validators' requirements: - CPU: ≥6cores, ≥12 threads - Memory: ≥64GB - Disk: SSD or NVMe ≥1.92 TB total - Bandwidth: ≥1Gbit/s guaranteed ## Note Participating as a validator is temporarily allowed only for whitelisted accounts. The Upshot Team currently has access to whitelisted addresses. We plan to make this action permissionless soon. In the meantime, those interested in becoming validators should reach out [here](https://docs.google.com/forms/d/e/1FAIpQLScj2rGAjFAAPZANrr2vZr_WAmLhniHn2x_l8K7EQcJ1i8XqHw/viewform). ## Responsibilities Validators are responsible for operating most of the infrastructure associated with instantiating the Allora Network. They do this in three ways: 1. Staking in worker nodes (data scientists) based on their confidence in said workers' abilities to produce accurate inferences. 2. Operating the appchain as Cosmos validators. ## Executing Loss-Calculation Logic Off-Chain The topic-specific logic ran by validators is compiled to WASM and stored on IPFS. Our appchain calls upon validators to execute this logic in every `topic.loss_cadence`-length epoch. Running this WASM involves querying for the following values: - Current set of losses between reputers and workers - Inferences from the past epoch - The revealed ground truth consisting of up to `topic.inference_cadence/topic.loss_cadence`-many values. In other words, it entails one ground truth value for each inference cadence within the preceding loss-calculation epoch. The new losses are then committed to the appchain in a transaction. Computing loss-calculation logic off-chain saves the network validators operating expenses (because less is run on-chain), allows topic creators to write loss-calculation logic in any language (that compiles to WASM), and lessens the need for frequent node software upgrades (because the module source code remains unchanged even as new topics are added, each with their specific loss-calculation schemes). --- # Deploy Allora Appchain Source: https://docs.allora.network/operate/validators/deploy-chain We discuss the settlement layer for the Allora Network and how to deploy it. > We discuss the settlement layer for the Allora Network and how to deploy it ## What is the Appchain? The Allora Appchain is a Cosmos SDK appchain that serves as the settlement layer for the Allora Network. It serves to coordinate all incentives for all actors: - The weights between reputers and workers, as well as a reference to the logic used to update those weights, are stored on-chain. - Rewards payable from inflation are calculated based on those weights at a global cadence on-chain. - Consumers pay for inferences to be collected and for all the above calculations to run. These funds get allocated to workers and reputers, respectively. The appchain also coordinates actions between protocol actors. - The appchain triggers requests to workers and reputers to collect inferences and run loss-calculation logic, respectively, as per each topic's respective inference and loss-calculation cadence. - The appchain collects a recent history of inferences in batches to later be scored by loss-calculation. ## Why and How might one interact with the Allora Appchain? Different actors interact with the Allora Appchain for different reasons. They do so via a standard client connection (such as [CosmJS](https://tutorials.cosmos.network/tutorials/7-cosmjs/1-cosmjs-intro.html)) or the [Appchain CLI](https://docs.allora.network/get-started/cli#installing-allorad). - Data scientists interact with the Appchain to [register their worker nodes](https://docs.allora.network/reference/allorad#register-network-actor) and to [withdraw rewards](https://docs.allora.network/reference/allorad#remove-stake-from-a-topic) accrued for their inferences. These rewards are paid by both consumers and inflation based on their relative weight. - Developers interact with the Appchain to [create topics](https://docs.allora.network/reference/allorad#create-new-topic), fund topics, and perhaps also to [read recent inferences](https://docs.allora.network/reference/allorad#get-the-latest-network-inferences-and-weights-for-a-topic). - Validators run the Appchain and receive standard inflationary rewards for running Cosmos SDK appchains and a cut of the funds from consumers. They will also [register themselves](https://docs.allora.network/operate/validators/stake-a-validator) on the Appchain so that they can be eligible for rewards. ## Dependencies - Create a set of keys and initialize genesis. See example in `scripts/init.sh`. - The script `scripts/l1_node.sh` is provided too, to facilitate configuration and maintenance of the node when connecting it to a network: it runs `allorad init`, downloads that network's genesis file, seeds and peers, and then starts the node against them. ## Deploy with docker-compose There is a `docker-compose.yml` provided that sets up a validator node. ### Run Once this is set up, run `docker compose up`. ## Deploy in k8s with helm chart Upshot team uses a [universal-helm](https://upshot-tech.github.io/helm-charts/) chart to deploy applications into kubernetes clusters. The chart ships an [`example--allora-validator.yaml`](https://github.com/upshot-tech/helm-charts/blob/main/charts/universal-helm/example--allora-validator.yaml) values file that sets up the node components. Download it and edit it for your environment before installing. ### Dependencies - You need to have configured `kubeconfig` file on the computer to connect to the cluster and deploy the node. ### Deploy with the Helm Chart 1. Add upshot Helm chart repo: ```bash helm repo add upshot https://upshot-tech.github.io/helm-charts ``` 2. Install helm chart with the given values file: ```bash helm install \ allora-validator \ upshot/universal-helm \ -f example--allora-validator.yaml ``` ### Edit Chain Parameters The public mainnet uses standard cosmos governance modules to vote on global network parameters (such as reward epoch time in blocks, for example). For testnets and devnets, however, you can use the following allorad CLI command to set the global parameters of the blockchain if you are whitelisted to do so. The parameters below are just example values: ```Text bash allorad tx emissions update-params "$VALIDATOR_KEY_FOR_TX_SEND" '{"version":["v0.0.4"], "min_topic_weight":["5"], "max_topics_per_block":[50]}' ``` --- # Running a full node Source: https://docs.allora.network/operate/validators/run-full-node How to become a Validator on Allora. > How to become a Validator on Allora This guide provides instructions on how to run a full node for the Allora network. There are two primary methods for running an Allora node: using systemd with cosmosvisor for easier upgrade management (recommended) or using docker compose. It's important to choose the method that best suits your environment and needs. *** ## Prerequisites - Git - Go (version 1.21 or later) - Basic command-line knowledge - Linux/Unix environment with systemd - curl and jq utilities *** ## Method 1: Using systemd with cosmosvisor (Recommended) Running the Allora node with systemd and cosmosvisor provides production-grade reliability and easier binary upgrade management. This is the recommended approach for validators and production environments. ### Step 1: Install cosmosvisor First, install cosmosvisor, which will manage binary upgrades: ```shell go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@latest ``` Verify the installation: ```shell cosmovisor version ``` ### Step 2: Install allorad Binary Download the latest `allorad` binary from the releases page: 1. Navigate to the [Allora Chain Releases page](https://github.com/allora-network/allora-chain/releases/latest). 2. Download the `allorad` binary appropriate for your operating system (e.g., `allorad-linux-amd64`, `allorad-darwin-amd64`). 3. Rename and move the binary to a standard location: ```shell # Rename the downloaded binary mv ./allorad-linux-amd64 ./allorad # Adjust filename as needed # Move to system path sudo mv ./allorad /usr/local/bin/allorad # Make executable sudo chmod +x /usr/local/bin/allorad ``` ### Step 3: Initialize the Node Initialize your node (replace `` with your desired node name): ```shell allorad init --chain-id allora-testnet-1 ``` ### Step 4: Download Network Configuration Download the testnet configuration files: ```shell # Download genesis.json curl -s https://raw.githubusercontent.com/allora-network/networks/main/allora-testnet-1/genesis.json > $HOME/.allorad/config/genesis.json # Download config.toml curl -s https://raw.githubusercontent.com/allora-network/networks/main/allora-testnet-1/config.toml > $HOME/.allorad/config/config.toml # Download app.toml curl -s https://raw.githubusercontent.com/allora-network/networks/main/allora-testnet-1/app.toml > $HOME/.allorad/config/app.toml ``` ### Step 5: Configure Seeds and Peers Configure seeds and persistent peers for network connectivity: ```shell # Fetch and set seeds SEEDS=$(curl -s https://raw.githubusercontent.com/allora-network/networks/main/allora-testnet-1/seeds.txt) sed -i.bak -e "s/^seeds *=.*/seeds = \"$SEEDS\"/" $HOME/.allorad/config/config.toml # Optionally set persistent peers PEERS=$(curl -s https://raw.githubusercontent.com/allora-network/networks/main/allora-testnet-1/peers.txt) sed -i.bak -e "s/^persistent_peers *=.*/persistent_peers = \"$PEERS\"/" $HOME/.allorad/config/config.toml ``` ### Step 6: Configure cosmosvisor Set up the cosmosvisor directory structure and environment: ```shell # Set environment variables export DAEMON_NAME=allorad export DAEMON_HOME=$HOME/.allorad export DAEMON_RESTART_AFTER_UPGRADE=true # Create cosmosvisor directories mkdir -p $DAEMON_HOME/cosmovisor/genesis/bin mkdir -p $DAEMON_HOME/cosmovisor/upgrades # Copy the current binary to genesis cp /usr/local/bin/allorad $DAEMON_HOME/cosmovisor/genesis/bin/ ``` ### Step 7: Configure State Sync (Optional but Recommended) State sync allows your node to quickly catch up with the network. Create and run this state sync script: ```shell cat > state_sync.sh << 'EOF' #!/bin/bash set -e # Choose your preferred RPC endpoint SNAP_RPC="https://allora-rpc.testnet.allora.network" CONFIG_TOML_PATH="$HOME/.allorad/config/config.toml" echo "Using RPC Endpoint: $SNAP_RPC" echo "Fetching latest block height..." LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height) if [ -z "$LATEST_HEIGHT" ] || [ "$LATEST_HEIGHT" == "null" ]; then echo "Error: Could not fetch latest height" exit 1 fi BLOCK_HEIGHT_OFFSET=2000 BLOCK_HEIGHT=$((LATEST_HEIGHT - BLOCK_HEIGHT_OFFSET)) echo "Fetching trust hash for block $BLOCK_HEIGHT..." TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash) if [ -z "$TRUST_HASH" ] || [ "$TRUST_HASH" == "null" ]; then echo "Error: Could not fetch trust hash" exit 1 fi echo "Updating config for state sync..." RPC_SERVERS="$SNAP_RPC,$SNAP_RPC" sed -i.bak -E \ -e "s|^(enable[[:space:]]*=[[:space:]]*).*$|\\1true|" \ -e "s|^(rpc_servers[[:space:]]*=[[:space:]]*).*$|\\1\"$RPC_SERVERS\"|" \ -e "s|^(trust_height[[:space:]]*=[[:space:]]*).*$|\\1$BLOCK_HEIGHT|" \ -e "s|^(trust_hash[[:space:]]*=[[:space:]]*).*$|\\1\"$TRUST_HASH\"|" \ "$CONFIG_TOML_PATH" echo "State sync configuration updated successfully" EOF chmod +x state_sync.sh ./state_sync.sh ``` ### Step 8: Reset Node Data Reset existing data while keeping the address book: ```shell allorad comet unsafe-reset-all --home $HOME/.allorad --keep-addr-book ``` **Warning**: This command deletes blockchain data. Only run this on a fresh node or when you intend to resync from scratch. ### Step 9: Create systemd Service Create a systemd service file for cosmosvisor: ```shell sudo tee /etc/systemd/system/allorad.service > /dev/null < run `docker compose up -d` to run the container in detached mode, allowing it to run in the background. **Info**: Don't forget to pull the images first, to ensure that you're using the latest images. Make sure that any previous containers you launched are killed, before launching a new container that uses the same port. You can run the following command to kill any containers running on the same port: ```bash docker container ls docker rm -f ``` #### Run Only a Node with Docker Compose In this case, you will use Allora's heads. ##### Run ``` docker compose pull docker compose up node ``` To run only a head: `docker compose up head` **NOTE:** You can also comment out the `head` service in `docker-compose.yml`, so that a plain `docker compose up` never starts it. ### Monitoring Logs To view the node's logs, use the following command: ```shell docker compose logs -f ``` ### Executing RPC Calls You can interact with the running node through RPC calls. For example, to check the node's status: ```shell curl -s http://localhost:26657/status | jq . ``` This command uses `curl` to send a request to the node's RPC interface and `jq` to format the JSON response. Once your node has finished syncing and is caught up with the network, this command will return `false`: ```shell curl -so- http\://localhost:26657/status | jq .result.sync_info.catching_up ``` **Info**: The time required to sync depends on the chain's size and height. - For newly launched chains, syncing will take **minutes**. - Established chains like Ethereum can take around **a day** to sync using Nethermind or similar clients. - Some chains may take **several days** to sync. - Syncing an archival node will take significantly more time. **Warning**: Network participants will not be able to connect to your node until it is finished syncing and the command above returns `false`. ### Syncing from Snapshot Users can also opt to sync their nodes from our [latest snapshot script](https://github.com/allora-network/allora-chain/blob/main/scripts/restore_snapshot.sh) following the instructions below: 1. Install [`rclone`](https://rclone.org/), a command-line program to manage files on cloud storage ```bash brew install rclone ``` 2. Follow the instructions to configure `rclone` after running `rclone config` in the command line 3. Uncomment the [following lines](https://github.com/allora-network/allora-chain/blob/ccad6d27e55b27a7ec3b2aebd7e55f1bc26798ed/scripts/l1_node.sh#L15) from your Allora Chain repository: ```go # uncomment this block if you want to restore from a snapshot # SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # "${SCRIPT_DIR}/restore_snapshot.sh" ``` 4. Run the node using Docker: ```bash docker compose pull docker compose up -d ``` --- # Stake a Validator Source: https://docs.allora.network/operate/validators/stake-a-validator Follow these steps to stake on a node in the Allora network, including running and syncing a full node, funding your account, and setting up your Validator for staking. Follow these steps to stake on a node in the Allora network. This process includes running and syncing a full node, funding your account, and setting up your Validator for staking. ## Prerequisites - Successfully run and synced a full `allorad` node. Refer to [Running a Full Node](https://docs.allora.network/operate/validators/run-full-node) for detailed instructions. - Basic command-line and Docker knowledge. - Access to the node's terminal or command line. ## 1\. Verify Node Sync Ensure your node is fully synced with the network by executing the following command: ```shell curl -s http://localhost:26657/status | jq .result.sync_info.catching_up ``` Wait until the output returns `false`, indicating your node has caught up with the network. ## 2\. Fund Your Account After initializing your node, `scripts/l1_node.sh` generates key and account information, found in `data/*.account_info`. Locate your account address within this file to fund it. ```shell cat data/validator0.account_info - address: allo1xxxxx name: validator0 pubkey: xxx type: local [...] ``` For testnet environments, use the appropriate [faucet](https://docs.allora.network/get-started/setup-wallet#add-faucet-funds). ## 3\. Stake as a Validator To become a validator, perform the following inside the validator's Docker container environment. You can choose your validator's name by setting a custom moniker (with `--moniker=...`). We will take the example of `validator0` with `10000000 uallo`. ### Access the Validator's Shell Use `docker compose` to access the validator's shell environment: ```shell docker compose exec validator0 bash ``` **Note**: You can list all available keys with: ```shell allorad --home=$APP_HOME keys --keyring-backend=test list ``` ### Prepare Stake Information Within the validator's shell, create a JSON file named `stake-validator.json` with your validator's stake information. Replace values with your actual data: ```shell cat > stake-validator.json << EOF { "pubkey": $(allorad --home=$APP_HOME comet show-validator), "amount": "1000000uallo", "moniker": "$(echo $MONIKER)", "commission-rate": "0.1", "commission-max-rate": "0.2", "commission-max-change-rate": "0.01", "min-self-delegation": "1" } EOF ``` ### Execute the Stake Command With your stake information file ready, execute the following command to stake as a Validator: ```shell allorad tx staking create-validator ./stake-validator.json \ --chain-id=allora-testnet-1 \ --home="$APP_HOME" \ --keyring-backend=test \ --from="$MONIKER" ``` This command outputs a transaction hash, which can be checked on the network's explorer: `https://explorer.testnet.allora.network/allora-testnet-1/tx/$TX_HASH`. ## 4\. Verify Validator Setup Ensure your validator is properly registered and staked with the network by executing the following commands: ### Check Registration and Stake Retrieve and verify your validator's information by running these 2 commands: ```shell VAL_PUBKEY=$(allorad --home=$APP_HOME comet show-validator | jq -r .key) ``` ```shell allorad --home=$APP_HOME q staking validators -o=json | \ jq '.validators[] | select(.consensus_pubkey.value=="'$VAL_PUBKEY'")' ``` This command outputs detailed information about your validator. If it's correctly set up, it will look like this: ```json { "operator_address": "allovaloper1n8t4ffvwstysveuf3ccx9jqf3c6y7kte48qcxm", "consensus_pubkey": { "type": "tendermint/PubKeyEd25519", "value": "gOl6fwPc19BtkmiOGjjharfe6eyniaxdkfyqiko3/cQ=" }, "status": 3, "tokens": "1000000", "delegator_shares": "1000000000000000000000000", "description": { "moniker": "val2" }, "unbonding_time": "1970-01-01T00:00:00Z", "commission": { "commission_rates": { "rate": "100000000000000000", "max_rate": "200000000000000000", "max_change_rate": "10000000000000000" }, "update_time": "2024-02-26T22:50:31.187119394Z" }, "min_self_delegation": "1" } ``` ### Check Voting Power Verify that your Validator's voting power is greater than 0, indicating active participation in the Network: ```shell allorad --home=$APP_HOME status | jq -r '.validator_info.voting_power' ``` **Note**: Please allow 30-60 seconds for the information to update. A voting power greater than 0 signifies a successful stake setup. Congratulations! --- # Validator Operations Source: https://docs.allora.network/operate/validators/validator-operations Common validator operations on the Allora chain, including unjailing a validator and unbonding stake. ## Unjailing a validator To unjail a validator execute the following command from the validator ```Text bash allorad --home="$APP_HOME" \ tx slashing unjail --from $VALIDATOR_ADDRESS ``` ## Unstaking/unbounding a validator If you need to delete a validator from the chain, you just need to unbound the stake with your custom parameters: ```bash allorad --home="$APP_HOME" \ tx staking unbond ${VALIDATOR_OPERATOR_ADDRESS} \ ${STAKE_AMOUNT}uallo --from "$MONIKER" \ --keyring-backend=test --chain-id ${NETWORK} ``` --- # Software Upgrades Source: https://docs.allora.network/operate/validators/software-upgrades How to upgrade the Allora software version during hard forks. > How to upgrade the Allora software version during hard forks. The Allora network relies on multiple different pieces of software to do different tasks. For example the `allora-chain` repository handles the blockchain software that runs the chain, while off-chain participants such as workers and reputers run their own software. Each piece of software may need to be upgraded separately. ## Allora-Chain Upgrades The `allora-chain` software is a cosmos-sdk based blockchain that runs the Allora network. New software releases are published on the Allora Chain [Github](https://github.com/allora-network/allora-chain/releases) page and are tagged with a version number. Upgrading to non-breaking versions is as simple as downloading the pre-built binaries or compiling the software from source and running the new version. ### Upgrading to a Breaking Version For breaking versions such as hard forks, or software upgrades requiring changes to the underlying state machine of the allora-chain, the upgrade process is more involved. These upgrades require using the `gov` and `upgrade` cosmos-sdk modules to first propose and vote on a software upgrade, and then to execute the upgrade at a specific block height. #### For Allora Chain Developers For writing an upgrade the steps are roughly the following: 1. In the `app/` [folder](https://github.com/allora-network/allora-chain/tree/main/app/upgrades), create a new folder for your upgrade. 2. In that folder create a file that contains an `UpgradeName`, and a function `CreateUpgradeHandler` which returns a `"cosmossdk.io/x/upgrade/types".UpgradeHandler`.Optionally include a `UpgradeInfo` that is a json string telling the client software where to download the upgrade binary version e.g. ```golang const UpgradeInfo = `'{"binaries":{"linux/amd64":"https://github.com/allora-network/allora-chain/releases/download/v9.9.9/allorad_amd64.tar.gz"}}'` ``` 3. Wire up the new upgrade handler to the chain by adding it to the `upgradeHandlers` list in [app/upgrades.go](https://github.com/allora-network/allora-chain/blob/main/app/upgrades.go), which the `setupUpgradeHandlers` function registers on the chain. The previous upgrade handlers already wired up in that file serve as a reference. 4. If you're upgrading standard cosmos-sdk module versions you may have to tweak the `module.VersionMap` that the `CreateUpgradeHandler` returns/processes. 5. If you're upgrading one of the Allora forked/created modules, you'll need to bump the `ConsensusVersion` for the module. 6. In the module, have the `module.Configurator` do a `cfg.RegisterMigration` with the module name, the previous consensus version that is being upgraded from, and the function to run to do the migration as a parameter. 7. Write a function that process the kv store or does whatever other migrations are necessary. Examples [here](https://github.com/allora-network/allora-chain/blob/main/x/emissions/migrations/v2/migrate.go) and [here](https://github.com/evmos/evmos/blob/v20.0.0/x/evm/migrations/v7/migrate.go). 8. Merge the PR, tag it appropriately and post it to the releases page. 9. Create a Software Upgrade Proposal for validators to vote on. You can see a reference where this is done in the [proposeUpgrade](https://github.com/allora-network/allora-chain/blob/main/test/integration/upgrade_test.go) function in the integration tests. 10. Convince all the validators to vote yes on the Software Upgrade Proposal, and run cosmovisor so that the upgrade will actually go through at the proposed block. #### For Allora Chain Validator Operators For those running the chain software, you will have to have to perform an upgrade as follows: 1. Make sure you're running the `allorad` software with [Cosmovisor](https://docs.cosmos.network/sdk/v0.50/build/tooling/cosmovisor)) managing the process, `DAEMON_NAME=allorad` and `DAEMON_HOME=/path/to/allorad/data/folder`. Hopefully you've already run `cosmovisor init /path/to/allorad-binary` and have the `/allorad/data/folder/cosmovisor` set. 2. At some point the blockchain developers will provide you with a binary to put in that `/allorad/data/folder/cosmovisor` folder to upgrade to. This may be optional if the `UpgradeInfo` is set correctly by the developers, but if you're the paranoid type you can always download the binary yourself ahead of the upgrade and put it in the right folder by hand. 3. When the developers put up the upgrade proposal to governance, be helpful and vote to make it pass. You can do this via the CLI with `allorad tx gov vote $proposal_id yes --from $validator` or an example of doing this programmatically can be found in the integration test [voteOnProposal](https://github.com/allora-network/allora-chain/blob/main/test/integration/upgrade_test.go) function. 4. At the block height of the upgrade, the old software will panic - cosmovisor will catch the panic and restart the process using the new binary for the upgrade instead. Monitor your logs appropriately to see the restart. ## Further References This is probably the most helpful document to understand the full workflow of a cosmos-sdk chain upgrade: [Medium Blog Post Cosmos Dev Series: Cosmos Blockchain Upgrade](https://medium.com/web3-surfers/cosmos-dev-series-cosmos-sdk-based-blockchain-upgrade-b5e99181554c) Cosmos SDK Upgrade Module: [Documentation](https://docs.cosmos.network/sdk/v0.50/build/modules/upgrade) Cosmovisor Process Manager Software [Documentation](https://docs.cosmos.network/sdk/v0.50/build/tooling/cosmovisor) Cosmos SDK Gov Module: [Documentation](https://docs.cosmos.network/sdk/v0.50/build/modules/gov) --- # Topic Life Cycle Source: https://docs.allora.network/operate/topics/lifecycle The Topic Life Cycle in the Allora Network is a dynamic process that determines the stages a topic goes through from creation to conclusion. The Topic Life Cycle in the Allora Network is a dynamic process that determines the stages a topic goes through from creation to conclusion. These stages are influenced by various factors such as funding, popularity, and performance metrics. Understanding the life cycle of a topic is crucial for engaging with the network. ## Key Terms and Concepts ### Epoch Length How often inferences are sampled and scored in the topic. Defined when [creating a topic](https://docs.allora.network/operate/topics/create) as `EpochLength`. ### Epoch Last Ended The timestamp indicating when the last epoch ended, important for tracking topic activity. ### Ground Truth Lag The amount of time into the future a specific inference is calculating for. Defined when [creating a topic](https://docs.allora.network/operate/topics/create) as `GroundTruthLag`. E.g. "Every 15 minutes, provide BTC prediction for 1 day in the future": - 10 min - EpochLength - 1 day - GroundTruthLag ### Nonce The block height at which a given outbound request from network validators is made. Nonces ensure that responses are correctly paired with their requests to facilitate accurate reward distribution and loss calculation. Every topic will inevitably generate multiple worker and reputer requests, each needing to be matched with rewards for participants. The blockchain must differentiate between responses still pending rewards and those already rewarded, and reputers must identify which worker payloads to use for loss calculations. This requires uniquely identifying each outbound request. The same nonce value will be used to fulfill a complete work and reputation cycle: 1. A request for inferences and forecasts using a particular nonce is issued first. 2. Once the workers have submitted their work, the worker nonce is fulfilled and a reputer nonce is created using the same value. 3. This reputer nonce will be processed when appropriate, triggering a reputation request. 4. When the reputers respond by submitting their work, the reputer nonce is also fulfilled, ending its cycle. ### Topic Competitiveness Competitiveness in the Allora Network refers to a topic's ability to attract and retain funding, stakes, and participation relative to other topics. A competitive topic has the following characteristics: - **High Effective Revenue**: A greater accumulation of revenue indicates strong interest. - **Significant Stake**: Large amounts of reputer and delegated stakes signify confidence in the topic's value. Both of these metrics are a function of [weight](https://docs.allora.network/operate/topics/lifecycle#weight), which proxies overall participation and ultimately topic competitiveness. ### Effective Revenue Effective Revenue is the measure of the impact that the total accrued revenue has on a topic's weight. It determines how much influence the revenue has on making a topic active and competitive. - Initially, Effective Revenue equals the total amount of money a topic accrues before the first epoch. - Once a topic becomes active, funds from Effective Revenue are used, impacting the ecosystem bucket. The Effective Revenue drips over time, reflecting the topic's diminishing competitiveness relative to other topics. ### Ecosystem Bucket The Ecosystem Bucket is a mechanism that distributes a portion of the total funds at a rate (approximately 10%) that decreases exponentially over time. This bucket serves as a comparative baseline for topic competitiveness. The effective revenue of a topic needs to be balanced with the ecosystem bucket to ensure the topic's competitiveness. - The bucket holds the money and drips at a certain rate. - This rate is uncoupled from the effective revenue drip to avoid complex calculations to determine how much effective revenue the topic actually has remaining. - It provides an estimation but doesn’t have a bearing on the total amount of money dripped from the ecosystem, ensuring financial safety. ### Weight Weight is a measure of a topic's competitiveness within the blockchain network. It is a function of the combined stake of reputers (including delegated stakes) and the topic's Effective Revenue. The weight of a topic determines its likelihood of becoming active and indirectly influences the distribution of rewards and resources within the network. - Higher weight signifies greater competitiveness. - Driven by the total stake and the impact of effective revenue. ## Topic States ### Inactive A topic is inactive after it is created but before it becomes sufficiently funded. ### Active A topic becomes active once it is sufficiently funded. A topic is sufficiently funded once it has more than a threshold amount of weight, which is a function of the amount of: - [Reputer stake](https://docs.allora.network/build/reputer/set-and-adjust-stake) placed in the topic - Delegated stake - Effective revenue garnered by the topic Different actors can permissionlessly [fund a topic](https://docs.allora.network/reference/allorad#send-funds-to-a-topic-to-pay-for-inferences) using the `allorad` CLI tool. ### Churnable A topic becomes churnable once it is: - Active - One of the top topics by weight (descending) - The topic's `EpochLength` has passed since its inception or last epoch Once a topic is churnable, the chain can emit worker (and eventually reputer) requests to topic workers and reputers, respectively. Reputer requests start after a topic's `GroundTruthLag` amount of blocks have passed. Once worker and reputer responses are fulfilled, the topic becomes _churned_. ### Rewardable A topic is rewardable once: - It has been churned - It has fulfilled worker and reputer requests - It is ready to have its rewards calculated --- # How to Create a Topic Source: https://docs.allora.network/operate/topics/create Inferences for the same domain are aggregated into the same topic. > Inferences for the same domain are aggregated into the same topic ## What is a Topic? Topics are [Schelling points](https://en.wikipedia.org/wiki/Focal_point_(game_theory)) where disparate-but-alike data scientists and domain experts aggregate their predictions. For example, we might create a topic for predicting the future price of ETH. There, all experts with any talent in predicting the future price of ETH will submit their inferences. Topics vary by domain and parameterization, defining how these inferences are collected and valued. Developers can make topics for arbitrary categories of inferences so long as they complete these steps: ## Prerequisites: 1. A wallet with sufficient funds to at least cover gas. Use [the faucet](https://docs.allora.network/get-started/setup-wallet) to get funds. 2. [Allorad CLI tool](https://docs.allora.network/get-started/cli#installing-allorad) ## Explainer Video Please see the video below to get a full deep-dive on the different parameters that make up a topic: [How to create a Topic](https://www.youtube.com/embed/WfM3Nrkgh6Y?si=Syap6TMjU7usLwVH) ## Tx Functions These functions write to the appchain. Add the **Command** value into your query to retrieve the expected data. ```bash allorad tx emissions [Command] ``` ## Creating Your First Topic The transaction for creating a topic has the following structure: ```go type MsgCreateNewTopic struct { // Address of the wallet that will own the topic Creator string `json:"creator,omitempty"` // Information about the topic Metadata string `json:"metadata,omitempty"` // The method used for loss calculations LossMethod string `json:"loss_method,omitempty"` // The frequency (in blocks) of inference calculations (Must be greater than 0) EpochLength int64 `json:"epoch_length,omitempty"` // The time it takes for the ground truth to become available (Cannot be negative) GroundTruthLag int64 `json:"ground_truth_lag,omitempty"` // the time window within a given epoch that worker nodes can submit an inference WorkerSubmissionWindow int64 `json:"worker_submission_window"` // Raising this parameter raises how much high-quality inferences are favored over lower-quality inferences (Must be between 2.5 and 4.5) PNorm github_com_allora_network_allora_chain_math.Dec `json:"p_norm"` // Raising this parameter lowers how much workers historical performances influence their current reward distribution (Must be between 0 and 1) AlphaRegret github_com_allora_network_allora_chain_math.Dec `json:"alpha_regret"` // Indicates if the loss function's output can be negative. If false, the reputer submits logs of losses; if true, the reputer submits raw losses. AllowNegative bool `json:"allow_negative,omitempty"` // the numerical precision at which the network should distinguish differences in the logarithm of the loss Epsilon github_com_allora_network_allora_chain_math.Dec `json:"epsilon"` MeritSortitionAlpha github_com_allora_network_allora_chain_math.Dec `json:"merit_sortition_alpha"` ActiveInfererQuantile github_com_allora_network_allora_chain_math.Dec `json:"active_inferer_quantile"` ActiveForecasterQuantile github_com_allora_network_allora_chain_math.Dec `json:"active_forecaster_quantile"` ActiveReputerQuantile github_com_allora_network_allora_chain_math.Dec `json:"active_reputer_quantile"` // Restrict inference/forecast submissions to whitelisted workers EnableWorkerWhitelist bool `json:"enable_worker_whitelist,omitempty"` // Restrict loss submissions to whitelisted reputers EnableReputerWhitelist bool `json:"enable_reputer_whitelist,omitempty"` // Per-topic normalization constant used when mapping regrets to weights CNorm github_com_allora_network_allora_chain_math.Dec `json:"c_norm"` // --- Multi-label / classification (added in v0.17.0) --- // Topic type: 1 = TOPIC_TYPE_REGRESSION, 2 = TOPIC_TYPE_CLASSIFICATION TopicType TopicType `json:"topic_type,omitempty"` // Output arity: 1 = TOPIC_OUTPUT_ARITY_SINGLE, 2 = TOPIC_OUTPUT_ARITY_MULTI OutputArity TopicOutputArity `json:"output_arity,omitempty"` // For classification topics: require the per-label outputs to sum to one RequireUnity bool `json:"require_unity,omitempty"` // Tolerance applied to the unity (sum-to-one) constraint UnityTolerance github_com_allora_network_allora_chain_math.Dec `json:"unity_tolerance"` // Cap on the number of labels a single worker may submit in one payload (multi-output topics) MaxLabelsPerSubmission uint64 `json:"max_labels_per_submission,omitempty"` // Optional allowlist of permitted (canonicalized) label names; empty means unrestricted LabelWhitelist []string `json:"label_whitelist,omitempty"` // Default value used for missing label slots in dense multi-label vectors LabelDefaultValue github_com_allora_network_allora_chain_math.Dec `json:"label_default_value"` // If false (default), label names are lowercased when canonicalized ("Cat" == "cat"); // immutable after topic creation LabelCaseSensitive bool `json:"label_case_sensitive,omitempty"` } ``` Using the [`allorad` CLI](https://docs.allora.network/get-started/cli#installing-allorad) to create a topic: The command takes 25 positional arguments, in this order. The example below passes the value shown in the right-hand column for each one: | # | Argument | Value in the example | |---|----------|----------------------| | 1 | `creator` | `"$YOUR_ADDRESS"` | | 2 | `metadata` | `"ETH prediction in 24h"` | | 3 | `loss_method` | `"mse"` | | 4 | `epoch_length` | `3600` | | 5 | `ground_truth_lag` | `0` | | 6 | `worker_submission_window` | `3` | | 7 | `p_norm` | `3` | | 8 | `alpha_regret` | `1` | | 9 | `allow_negative` | `true` | | 10 | `epsilon` | `0.001` | | 11 | `merit_sortition_alpha` | `0.1` | | 12 | `active_inferer_quantile` | `0.25` | | 13 | `active_forecaster_quantile` | `0.25` | | 14 | `active_reputer_quantile` | `0.25` | | 15 | `enable_worker_whitelist` | `false` | | 16 | `enable_reputer_whitelist` | `false` | | 17 | `c_norm` | `0.75` | | 18 | `topic_type` | `1` (regression) | | 19 | `output_arity` | `1` (single output) | | 20 | `require_unity` | `false` | | 21 | `unity_tolerance` | `0` | | 22 | `max_labels_per_submission` | `1` | | 23 | `label_whitelist` | `'[]'` (empty = unrestricted) | | 24 | `label_default_value` | `0` | | 25 | `label_case_sensitive` | `false` | Set `YOUR_ADDRESS`, `RPC_URL` and `CHAIN_ID` in your shell, then run: ```shell bash allorad tx emissions create-topic \ "$YOUR_ADDRESS" \ "ETH prediction in 24h" \ "mse" \ 3600 \ 0 \ 3 \ 3 \ 1 \ true \ 0.001 \ 0.1 \ 0.25 \ 0.25 \ 0.25 \ false \ false \ 0.75 \ 1 \ 1 \ false \ 0 \ 1 \ '[]' \ 0 \ false \ --node "$RPC_URL" \ --chain-id "$CHAIN_ID" ``` Be sure to swap out [`RPC_URL`](https://docs.allora.network/get-started/setup-wallet#rpc-url-and-chain-id), `YOUR_ADDRESS`, [`CHAIN_ID`](https://docs.allora.network/get-started/setup-wallet#rpc-url-and-chain-id) and all other arguments as appropriate with the desired values. The example above creates a standard **single-output regression topic** — the historical default, and what most price/quantity prediction topics use. The last eleven arguments (`enable_worker_whitelist` through `label_case_sensitive`) configure whitelisting and the multi-label features introduced in v0.17.0; see the section below. ### Notes An explanation in more detail of some of these fields. - `Metadata` is a descriptive field to let users know what this topic is about and/or any specific indication about how it is expected to work. - `allowNegative` determines whether the loss function output can be negative. - If **true**, the reputer submits raw losses. - If **false**, the reputer submits logs of losses. ## Topic Types, Output Arity, and Labels Starting in **v0.17.0**, a topic declares what kind of output it produces. These fields are set at creation and, except for the label registry, cannot be changed afterwards. - **`topic_type`** — `1` for **regression** (numeric prediction, e.g. the price of ETH) or `2` for **classification** (predicting the likelihood of discrete outcomes). - **`output_arity`** — `1` for a **single** output value, or `2` for **multiple** labeled outputs. A single-output topic behaves exactly like topics did before v0.17.0. - **`require_unity`** / **`unity_tolerance`** — for classification topics, require the per-label outputs to sum to one (a probability distribution), within `unity_tolerance`. Multi-output topics attach a **label** to each value a worker submits (for example `up`, `down`, `flat`). The topic's **label registry** controls this: - **`max_labels_per_submission`** — the maximum number of labels a single worker may include in one payload. - **`label_whitelist`** — an optional allowlist of permitted label names. Leave it empty (`'[]'`) to accept any label; provide a list (e.g. `'["up","down","flat"]'`) to restrict submissions. Labels are canonicalized (UTF-8, NFC-normalized, trimmed) before comparison. - **`label_default_value`** — the value used for label slots a worker omits when building the dense multi-label vector. - **`label_case_sensitive`** — when `false` (the default), `Cat`, `CAT` and `cat` collapse to the same label; when `true` they are distinct. This flag is immutable after creation. A single-output topic internally uses the canonical label `y`, which is why single-output network inferences are still returned under a single value. `update-topic` performs a **full replacement** of the fields it accepts (including the label registry). In particular, sending an empty `label_whitelist` sets the topic to *unrestricted* rather than preserving the current list, so always re-send the full whitelist to keep a restriction. Label changes are rejected while a worker submission window is open. `topic_type`, `output_arity`, `require_unity` and `label_case_sensitive` cannot be changed after creation. --- ## Fund a Topic - **RPC Method:** `FundTopic` - **Command:** `fund-topic [sender] [topic_id] [amount]` - **Description:** Sends funds to a specific topic to be used for paying for inferences or other topic-related activities. - **Positional Arguments:** - `sender`: The address of the sender providing the funds. - `topic_id`: The identifier of the topic to receive the funds. - `amount`: The amount of funds being sent to the topic. ### Use Case: **Why use it?** - This command is used to fund a topic, ensuring there are sufficient funds available to reward workers, forecasters, or other participants submitting inferences or engaging with the topic. **Example Scenario:** - As a network administrator or topic creator, you want to add funds to a topic to ensure that workers and forecasters are compensated for their contributions. --- # How to Query Topic Data using allorad Source: https://docs.allora.network/operate/topics/query To query topic-level data on the Allora chain using the allorad CLI, you need to interact with various RPC methods designed to return information about specific topics. To query topic-level data on the Allora chain using the `allorad` CLI, you need to interact with various RPC methods designed to return information about specific topics. ## Prerequisites - [`allorad` CLI](https://docs.allora.network/get-started/cli) ## Query Functions These functions read from the appchain only and do not write. Add the **Command** value into your query to retrieve the expected data. ```bash allorad q emissions [Command] --node ``` ### Get Topic by Topic ID - **RPC Method:** `GetTopic` - **Command:** `topic [topic_id]` - **Description:** Retrieves information about a specific topic by its ID. - **Positional Arguments:** - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - Use this command to query details about a particular topic. **Example Scenario:** - You want to check the metadata and settings for a specific topic in the network. --- ### Check if Topic Exists - **RPC Method:** `TopicExists` - **Command:** `topic-exists [topic_id]` - **Description:** Checks if a topic exists at the given ID. Returns `true` if the topic exists, `false` otherwise. - **Positional Arguments:** - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - Use this command to verify whether a topic has been created or is active in the network. **Example Scenario:** - Before interacting with a topic, you want to confirm that it exists in the system. --- ### Check if Topic is Active - **RPC Method:** `IsTopicActive` - **Command:** `is-topic-active [topic_id]` - **Description:** Checks whether a specific topic is currently active. Returns `true` if the topic is active, `false` otherwise. - **Positional Arguments:** - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - This command helps determine if a topic is active and available for participation. **Example Scenario:** - Before submitting any data, you want to confirm that the topic is active and accepting inputs. --- ### Get Next Topic ID - **RPC Method:** `GetNextTopicId` - **Command:** `next-topic-id` - **Description:** Returns the ID of the next available topic that can be created. #### Use Case: **Why use it?** - Use this command to determine the next available topic ID when creating a new topic. **Example Scenario:** - Before creating a new topic, you may want to check what the next topic ID will be. --- ### Get Reputer Stake in Topic - **RPC Method:** `GetReputerStakeInTopic` - **Command:** `stake-in-topic-reputer [address] [topic_id]` - **Description:** Retrieves the stake a reputer has in a specific topic, including any stake that has been delegated to them. - **Positional Arguments:** - `address`: The address of the reputer. - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - Use this command to check the total stake a reputer holds in a specific topic. **Example Scenario:** - You want to verify how much stake a particular reputer has in a specific topic. --- ### Get Total Stake Delegated to Reputer in a Topic - **RPC Method:** `GetDelegateStakeInTopicInReputer` - **Command:** `stake-total-delegated-in-topic-reputer [reputer_address] [topic_id]` - **Description:** Retrieves the total stake that has been delegated to a reputer in a specific topic. - **Positional Arguments:** - `reputer_address`: The address of the reputer. - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - Use this command to see how much stake has been delegated to a reputer in a topic. **Example Scenario:** - You want to check the total delegated stake assigned to a specific reputer. --- ### Get Delegate Stake Placement in Topic - **RPC Method:** `GetDelegateStakePlacement` - **Command:** `delegate-stake-placement [topic_id] [delegator] [target]` - **Description:** Retrieves the amount of tokens delegated to a specific reputer by a given delegator for a topic. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `delegator`: The address of the delegator. - `target`: The address of the target reputer. #### Use Case: **Why use it?** - This command allows delegators to track how much stake they have assigned to a reputer for a topic. **Example Scenario:** - You want to know how much stake you have delegated to a particular reputer in a specific topic. --- ### Get Delegate Stake Removal in a Topic - **RPC Method:** `GetDelegateStakeRemoval` - **Command:** `delegate-stake-removal [block_height] [topic_id] [delegator] [reputer]` - **Description:** Retrieves the current state of a pending delegate stake removal in a topic. - **Positional Arguments:** - `block_height`: The block height at which the removal is pending. - `topic_id`: The identifier of the topic. - `delegator`: The address of the delegator. - `reputer`: The address of the reputer. #### Use Case: **Why use it?** - Use this command to check the status of pending delegated stake removals in a topic. **Example Scenario:** - You want to know whether your request to remove delegated stake is still pending. --- ### Get Total Stake in Topic - **RPC Method:** `GetTopicStake` - **Command:** `topic-stake [topic_id]` - **Description:** Retrieves the total amount of stake, including delegate stake, in a specific topic. - **Positional Arguments:** - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - Use this command to check the total stake in a topic, including both direct and delegated stakes. **Example Scenario:** - You want to know the overall stake in a topic before participating or delegating more tokens. --- ### Get Latest Network Inferences for a Topic - **RPC Method:** `GetLatestNetworkInferences` - **Command:** `latest-network-inferences [topic_id]` - **Description:** Retrieves the latest network inference and weights for a given topic, using whatever information the network currently has available. - **Positional Arguments:** - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - This command is the primary way to get the most recent network-wide inference for a topic. **Example Scenario:** - You want to retrieve the latest ETH price prediction along with the worker and forecaster values that produced it. --- ### Get Topic Reward Nonce - **RPC Method:** `GetTopicRewardNonce` - **Command:** `topic-reward-nonce [topic_id]` - **Description:** Retrieves the reward nonce used to calculate rewards for a specific topic. - **Positional Arguments:** - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - Use this command to understand the reward cycle for a particular topic, as it provides the nonce used to calculate rewards. **Example Scenario:** - You want to check the reward nonce for a topic before submitting contributions. --- ### Get Topic Fee Revenue - **RPC Method:** `GetTopicFeeRevenue` - **Command:** `topic-fee-revenue [topic_id]` - **Description:** Retrieves the effective fee revenue for a topic, which represents the total fees collected by the topic less an exponential decay of the fees over time. - **Positional Arguments:** - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - This command provides insights into the fee revenue for a topic and how that impacts its overall weight and performance. **Example Scenario:** - You want to check the total fee revenue generated by a topic before adjusting its parameters or interacting further. --- ### Get Previous Topic Weight - **RPC Method:** `GetPreviousTopicWeight` - **Command:** `previous-topic-weight [topic_id]` - **Description:** Retrieves the previous weight of a topic, which can be used to estimate future or past topic performance. - **Positional Arguments:** - `topic_id`: The identifier of the topic. #### Use Case: **Why use it?** - Use this command to analyze the historical weight of a topic, which can help predict its future influence. **Example Scenario:** - You want to assess the past performance of a topic before participating in it again. --- ### Get Active Topics at Block - **RPC Method:** `GetActiveTopicsAtBlock` - **Command:** `active-topics-at-block [block_height]` - **Description:** Retrieves all active topics at a specific block height. - **Positional Arguments:** - `block_height`: The block height at which to retrieve the active topics. #### Use Case: **Why use it?** - Use this command to identify all topics that are active at a given block. **Example Scenario:** - You want to see which topics were active during a specific block height to compare performance or contributions. --- ### Get Topic Inferences at Block - **RPC Method:** `GetInferencesAtBlock` - **Command:** `inferences-at-block [topic_id] [block_height]` - **Description:** Retrieves all inferences produced for a topic at a given block height. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `block_height`: The block height for which to retrieve the inferences. #### Use Case: **Why use it?** - Use this command to get all inferences made for a topic at a specific block height. **Example Scenario:** - You want to analyze the inferences produced at a specific block for performance review or reward calculation. --- ### Get Topic Forecast Scores Until Block - **RPC Method:** `GetForecastScoresUntilBlock` - **Command:** `forecast-scores-until-block [topic_id] [block_height]` - **Description:** Retrieves all forecast scores for a topic until a specific block height, limited by `MaxSamplesToScaleScores`. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `block_height`: The block height for which to retrieve the forecast scores. #### Use Case: **Why use it?** - Use this command to track forecaster performance over time in a topic by looking at forecast scores until a specific block height. **Example Scenario:** - You want to evaluate the forecast scores for a topic until a particular block to assess forecaster accuracy. --- ### Get Reputer Scores at Block - **RPC Method:** `GetReputersScoresAtBlock` - **Command:** `reputer-scores-at-block [topic_id] [block_height]` - **Description:** Retrieves all reputer scores for a topic at a specific block height. - **Positional Arguments:** - `topic_id`: The identifier of the topic. - `block_height`: The block height for which to retrieve the reputer scores. #### Use Case: **Why use it?** - Use this command to evaluate how reputers performed at a specific block height. **Example Scenario:** - You want to analyze reputer performance at a particular block to understand how their contributions impacted the topic. --- --- # How to Query Network Data using allorad Source: https://docs.allora.network/operate/topics/query-network-data To query network-level data on the Allora chain using the allorad CLI, you need to interact with various RPC methods designed to return aggregate or holistic information about the network. To query network-level data on the Allora chain using the `allorad` CLI, you need to interact with various RPC methods designed to return aggregate or holistic information about the network. These methods enable you to pull data that is crucial for understanding the overall state and performance of the network. ## Prerequisites - [`allorad` CLI](https://docs.allora.network/get-started/cli) ## Query Functions These functions read from the appchain only and do not write. Add the **Command** value into your query to retrieve the expected data. ```bash allorad q emissions [Command] --node ``` ### Get Latest Network Inferences - **RPC Method:** `GetLatestNetworkInferences` - **Command:** `latest-network-inferences [topic_id]` - **Description:** Returns the latest network inference and weights for a given topic. The chain returns whatever information it currently has available for the topic. - **Positional Arguments:** - `topic_id`: The identifier of the topic for which you want to retrieve the latest network inference. An outlier-resistant variant (single-label regression topics only) is available as `GetLatestNetworkInferencesOutlierResistant` (`latest-network-inferences-outlier-resistant [topic_id]`). #### Use Case: **Why use it?** - This command is the primary way to retrieve the most recent network-wide inference for a topic. The response carries an `inference_block_height` field, so you can tell how recent the returned inference is before acting on it. **Example Scenario:** - You want the latest ETH price prediction produced by the network, together with the worker and forecaster values that fed into it. --- ### Get Total Rewards to Distribute - **RPC Method:** `GetTotalRewardToDistribute` - **Command:** `total-rewards` - **Description:** Returns the total amount of rewards that will be distributed across all rewardable topics in the current block. It provides an aggregate view of the rewards available for distribution. #### Use Case: **Why use it?** - This command is useful if you want to understand the total reward pool for a given block. It helps participants gauge the potential rewards available and how they may be distributed across topics based on performance. **Example Scenario:** - As a worker or forecaster, you might use this command to estimate the reward pool for the current block. This allows you to understand the potential total rewards before they are distributed across different topics and participants. --- ### Get Current Module Parameters - **RPC Method:** `GetParams` - **Command:** `params` - **Description:** Retrieves the current parameters of the module in the Allora network. It is used to check the configuration and settings that control various aspects of the module's behavior. - **Positional Arguments:** - This command does not require any positional arguments. #### Use Case: **Why use it?** - This command is useful for querying the configuration settings of the module. It provides transparency into how the module is configured and allows participants to verify whether certain parameters, such as reward distribution rules or other operational settings, are up-to-date. **Example Scenario:** - If you're troubleshooting the behavior of a module or need to verify the configuration before making any changes, this command can give you insight into the current parameters and their values. --- # Managing Gas with allorad Source: https://docs.allora.network/operate/gas-and-fees Invoking transactions causes network validators to do computations on your behalf and update the chain's state. These actions are compensated via _gas_. Invoking transactions causes network validators to do computations on your behalf and update the chain's state. These actions are compensated via _gas_. Gas is paid by wallets who send transactions to the Allora chain. In its [v0.7.0 release](https://github.com/allora-network/allora-chain/releases/tag/v0.7.0), Allora incorporated the [x/feemarket module](https://github.com/skip-mev/feemarket), which means that gas calculations follow an [EIP-1559-like schedule](https://help.coinbase.com/en/coinbase/getting-started/crypto-education/eip-1559) (see: the [original EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md)). This requires transactions to be structured differently from other cosmos chains. Prior to `allora-chain` `v0.7.0` and in many other Cosmos chains, transactions are typically structured like so: ``` allorad tx emissions ... --from ACCOUNT_NAME --node RPC --chain-id allora-testnet-1 --keyring-backend test --keyring-dir ~/.allorad/ --gas auto --gas-adjustment 1.2 --fees 2024700uallo ... ``` Since `v0.7.0`, transactions should instead abide by the structure: ``` allorad tx emissions ... --from ACCOUNT_NAME --node RPC --chain-id allora-testnet-1 --keyring-backend test --keyring-dir ~/.allorad/ --gas 130206 --gas-adjustment 1.2 --gas-prices 10uallo ... ``` To emphasize: This^^ is the way transactions should be structured today using `allorad`. The specific differences are: __`fees Xuallo` becomes `gas-prices 10uallo`__ - This is a config set in the network validators, so `10uallo` is the universally recommended value __`gas auto` becomes `gas 130206`__ - This value can change per the use case Other clients such as [CosmJS](https://github.com/cosmos/cosmjs) and [Ignite](https://docs.ignite.com/clients/go-client) would similarly need to include these flags when building transactions. --- # What is Allora? Source: https://docs.allora.network/learn/what-is-allora Allora is an open-source, decentralized marketplace for intelligence. Allora is an open-source, decentralized marketplace for intelligence. Examples of intelligence include, but are not limited to: - Insights about the future - Supervised and unsupervised learnings - Sentiment Analysis - Generative and Reinforcement Problems ## Overcoming Information Inefficiency The biggest challenge in the digital world is efficiently exchanging information. Efficient information exchange enables actors to make informed decisions across domains, from logistics and planning to governance and financial markets. When this information is accessible only to some ecosystem participants, they gain a unique advantage to beat the competition. At Allora, the intersection between blockchain technology and artificial intelligence (AI) provides an unprecedented opportunity to overcome information inefficiency. ## Introducing Allora The Allora Network is a state-of-the-art protocol that uses decentralized AI and machine learning (ML) to build and deploy predictions among its participants. It offers actors who wish to use AI predictions a formalized way to obtain the output of state-of-the-art ML models on-chain and to pay the operators of AI/ML nodes who create these predictions. Allora bridges the information gap between data owners, data processors, AI/ML predictors, market analysts, and the end-users or consumers who can execute these insights. The AI/ML agents within the Allora Network use their data and algorithms to broadcast their predictions across a peer-to-peer network, and they ingest these predictions to assess the predictions from all other agents. The network consensus mechanism combines these predictions and assessments and distributes rewards to the agents according to the quality of their predictions and assessments. This carefully designed incentive mechanism enables Allora to continually learn and improve, adjusting to the market as it evolves. ## More Info Allora aims to incentivize data scientists to provide high-quality inferences. This is achieved through a technical architecture detailed in the [Allora whitepaper](https://research.assets.allora.network/allora.0x10001.pdf) and implemented in the Allora Network GitHub repositories, particularly [`allora-chain`](https://github.com/allora-network/allora-chain) and the [`allora-sdk-py`](https://github.com/allora-network/allora-sdk-py) worker SDK. ## Learn More - [Developers](https://docs.allora.network/get-started) - [Community](https://github.com/allora-network/docs/blob/main/CONTRIBUTING.md) - [Participants](https://docs.allora.network/learn/participants) - [Inference Synthesis](https://docs.allora.network/learn/inference-synthesis) - [Consensus and Rewards](https://docs.allora.network/learn/consensus-and-rewards) - [Tokenomics](https://docs.allora.network/learn/tokenomics) ## How to Interact with the Network There are a few easy things a user could do to interact with the Allora Network quickly and efficiently, including installing CLI tools, creating a topic, and querying inferences off and on chain. - [Installation](https://docs.allora.network/get-started/cli#installing-allorad) - [Setup a Wallet](https://docs.allora.network/get-started/setup-wallet) - [Delegating Stake](https://docs.allora.network/learn/staking) - [Basic Usage](https://docs.allora.network/get-started/basic-usage) - [Allora Forge Competitions](https://docs.allora.network/build/forge/competitions) - [Query Inferences](https://docs.allora.network/operate/topics/query-network-data) ## Questions? Join the Allora Network [Community](https://github.com/allora-network/docs/blob/main/CONTRIBUTING.md) to ask for support, help improve Allora, or showcase what you built with Allora. --- # Key Terminology Source: https://docs.allora.network/learn/key-terms Definitions of the key terms used across the Allora Network and its documentation. ## Topics [Schelling Points](https://en.wikipedia.org/wiki/Focal_point_(game_theory)) that focus the efforts of the protocol by categorizing inferences. Anyone (identified as topic creators) can permissionlessly create a topic on Allora and define a **rule set** that determines how to reward correct inferences within said topic. Workers can then submit inferences to these topics and earn rewards based on how accurate their inferences are. ### Rule Set Loss calculation logic determined at topic creation by a topic creator who decides how to evaluate inferences, and consists of: - The loss function to use (e.g., mean absolute directional loss, L1-norm) - The source of ground truth (e.g., some endpoint, some oracle, the median of gathered inferences) ### Topic Types Since v0.17.0, a topic declares the kind of output it produces: - **Regression topics** predict a numeric value (e.g. the future price of ETH). - **Classification topics** predict the likelihood of discrete outcomes, and can optionally require those outcomes to sum to one (a probability distribution). A topic also declares its **output arity** — whether it produces a **single** value or **multiple** labeled values (see Labels). ### Labels Names attached to the individual values a worker submits to a **multi-output** topic (for example `up`, `down`, `flat`). Each topic maintains a **label registry** and may restrict the permitted labels via an allowlist, cap how many labels a worker may submit, and define a default value for omitted labels. Single-output topics use one canonical label (`y`) internally. ## Inferences Predictions or conclusions made by workers about specific outcomes within a given topic. ## Forecasts Predictions made by workers about the performance of their peers in the current epoch, expressed as a set of forecasted losses in accordance with the topic's loss function. Forecasts are used to gauge the reliability and accuracy of the participants' inferences within the specific context provided by the current circumstances. Forecasts and predictions are used interchangeably throughout the docs when referring to the output of forecasters. ## Context Awareness An additional dimension of evaluation that enables the network to achieve the best inferences under any circumstances using inferences and forecasts provided by workers. By incorporating feedback from the test set (live, revealed ground truth plus the live, revealed performances of one's peers), both inference and forecast models of individual workers can be improved over time. This improves overall network performance. By incentivizing forecasts, workers are incentivized to understand the contexts in which they and their peers perform well or poorly. For example, forecasters may understand that a subset of workers perform better on Wednesdays, whereas another performs well on Thursdays, or some do well in bear markets and others in bull markets. Integrating such context-aware insights empowers Allora to admit better performance than any individual actor because it can selectively leverage insights from the appropriate actors in the appropriate contexts. ## Network Inference The network's aggregate output for a topic in a given epoch — a weighted combination of the individual worker inferences and forecast-implied inferences. It is stored on-chain and served to consumers as a **network inference bundle** containing the combined value, the contributing inferer and forecaster values, a naive baseline, and one-out/one-in values used for scoring. Since v0.17.0 every value in the bundle is **labeled**, so multi-output topics return one value per label while single-output topics return a single value under the canonical label `y`. An optional **outlier-resistant** variant is produced for single-label regression topics. ## Network Participants A [network participant](https://docs.allora.network/learn/participants) in the Allora Network is an individual or entity that contributes and continuously adds value to the network by fulfilling specific roles. ## Supply Side All network participants that are not consumers. This includes workers, reputers, and validators. By contrast, the demand side is entirely informed by consumers or those who request inferences. ## Epochs Discrete periods during which inferences and forecasts are submitted, and rewards are distributed. Each epoch provides a timeframe for evaluating and scoring the performance of workers and reputers. ## Rewards Incentives given to workers and reputers based on their accuracy, performance and/or stake. These rewards are distributed at the end of each epoch, encouraging high-quality contributions. ## Stake A financial commitment made by reputers to show confidence in their ability to assess reputation by sourcing the truth and comparing it to workers' inferences. This stake increases the importance and rewards of a topic. Participants use the Allora chain CLI to stake. ### Delegated Stake A method for passive earnings where funds are delegated to a reputer, allowing the delegator to receive rewards based on the reputer's performance. - These delegated funds enhance the reputer's stake, improving topic security and the accuracy of loss reports - A withdrawal delay prevents quick attacks - Delegating involves risk but offers rewards based on the reputer's success #### Withdrawal Delay Allora enforces a mandatory waiting period for withdrawals of stake and rewards to enhance security. When you request a withdrawal, you must: 1. Initiate the withdrawal 2. Wait for the specified delay before the withdrawal executes This two-step process helps protect against flash attacks while maintaining a smooth user experience. ## Regrets A measure of how the performance of a worker’s inference compares to the network’s previously reported accuracy. A positive regret implies that the inference of worker `x` outperforms the network, whereas a negative regret implies the network outperforms worker `x`. --- # Allora Network Participants Source: https://docs.allora.network/learn/participants The roles Allora Network participants fulfill — workers, reputers, validators, and consumers — and how to find yours. Allora Network participants can fulfill a variety of different roles after any of these participants have created a topic. A topic is registered on the Allora chain with a short rule set governing network interaction, including the loss function that needs to be optimized by the topic network. Allora Labs will contribute to the development of the network alongside other external code contributors. Allora Labs will also participate in the network as a worker by running models. Allora Labs will contribute as a sales/marketing service provider for Allora. - **Workers** provide AI/ML-powered inferences to the network. These inferences can directly refer to the object that the network topic is generating or to the predicted quality of the inferences produced by other workers to help the network combine these inferences. A worker receives rewards proportional to the quality of its inferences. - **Reputers** evaluate the quality of the inferences provided by the workers. This is done by comparing the inferences to the ground truth when available. Reputers also quantify how much these inferences contribute to the network-wide inference. A reputer receives rewards proportional to its stake and the quality of its evaluations. Reputers are often authoritative domain experts to assess the quality of inferences accurately. - **Validators** are responsible for operating most of the infrastructure associated with instantiating the Allora Network by operating the appchain as Cosmos validators. Validators receive rewards proportional to their stake. - **Consumers** request inferences from the network. They pay for the inferences using the native network token. ## Find Your Role Participants can permissionlessly integrate with Allora to consume, supply, or verify the accuracy of exchanged inferences. On-chain consumer contracts are being rebuilt, and their documentation will return when the new contracts ship. In the meantime, inferences can be consumed through the [Allora API](https://docs.allora.network/consume/api). Here we'll help you find exactly what you're looking for. - Discover the best way to participate, for: - [Data Scientists (Workers)](https://docs.allora.network/build/overview): Experts in machine learning or domain-specific insights who want to contribute their knowledge to the network. - [Developers (Consumers)](https://docs.allora.network/consume/overview): Individuals or organizations seeking crowdsourced predictions to integrate into their applications. - [Validators](https://docs.allora.network/operate/validators): Those with the skills and resources to run hardware and ensure the security and integrity of the network. - [Data Providers (Reputers)](https://docs.allora.network/build/reputer): Contributors who supply reliable data to evaluate and ensure the accuracy of predictions. --- # Inference Synthesis Source: https://docs.allora.network/learn/inference-synthesis How the Allora network's three layers turn worker inferences and forecasts into a single network inference. ![layers-of-allora](https://docs.allora.network/layers-of-allora.jpg) The Allora network operates through three distinct layers: - **Inference Consumption Layer**: Facilitates the exchange of inferences. - **Forecasting and Synthesis Layer**: - Inference workers provide inferences. - Forecasting workers use models to predict the accuracy of these inferences. - The Inference Synthesis mechanism aggregates results for consumers. - **Consensus Layer**: - Manages rewards and economics for network participants. - Ensures a permissionless and secure environment for transactions. This page covers the first two layers: how inferences are exchanged, forecast, and synthesized into a single network inference. The consensus layer — rewards and economics — is covered in [Consensus and Rewards](https://docs.allora.network/learn/consensus-and-rewards). ## Inference Consumption ### Request/Response Flow At its core, Allora facilitates the exchange of inferences, enabling _Consumers_ to request them and _Workers_ to supply them. ![supply-demand](https://docs.allora.network/exchange-inferences.jpg) Learn how to query data and inferences [offchain](https://docs.allora.network/consume/api) and [onchain](https://docs.allora.network/operate/topics/query-network-data) for a given [topic](https://docs.allora.network/learn/key-terms#topics). ### Topic Coordination Inferences are categorized using Topics. Anyone, including network participants, can permissionlessly create topics to coordinate network collaboration. A single topic is stored inside a Topic Coordinator and is identified using a _rule set_, which consists of a target variable and a loss function which are used to score topic inferences. ![supply-demand](https://docs.allora.network/topic-coordinator.jpg) Inferences have a [topic life cycle](https://docs.allora.network/operate/topics/lifecycle) that governs their stages from creation to conclusion. ### Reputers As the number of workers in the network increases, some will naturally perform better than others due to the system's permissionless nature. To maintain quality and help the network set the reward distribution, Reputers evaluate each worker's performance against the ground truth when it becomes available. ![supply-demand](https://docs.allora.network/reputers.jpg) The final architecture of the inference consumption layer shows how consumers request inferences, how workers supply them, and how reputers verify the accuracy of inference workers. ## Forecast and Synthesis Inferences are scored by forecast workers and combined by the topic coordinator to deliver a single synthesized inference to the consumer that is a weighted combination of all individual inferences. Let's dive into this process in the following sections. ## Forecast ### Context Awareness Some workers function to forecast the expected performance of other workers inferences' and make the network **Context Aware**. [Context awareness](https://docs.allora.network/learn/key-terms#context-awareness) enables the aggregated inference produced by the network to be better than any individual model's output. Inference Synthesis is greatly enhanced due to the context awareness of the workers. ![forecast-initial](https://docs.allora.network/forecast-initial.jpg) ### Losses Some workers forecast, some workers produce inferences and some do both. Forecast workers use their own data and models to predict the accuracy of produced inferences, generating **forecasted losses**. Forecasted losses allow the network to become context aware. ![forecast-inference-workers](https://docs.allora.network/forecast-inference-workers.jpg) ### Regrets Forecasted losses are used to calculate **regret**, which indicates how much better or worse each inference is expected to be compared to previous inferences. Positive regret means an inference is expected to be more accurate than the network inference, while negative regret means it is expected to be less accurate. Regrets are used to generate weights, where more accurate inferences get higher weights. Losses and weights are collectively used to synthesize inferences. Let's dive into how inference synthesis works in the next section. ## Synthesis Inference synthesis in Allora is a process that combines individual inferences from various workers to produce an aggregate inference. This process takes place at each epoch and involves both inference and forecasting tasks. ### Normalization of Regrets Regrets are normalized to ensure weights are comparable and within a reasonable range. This allows the use of a single mapping function to map regrets to weights, independently of the absolute scale of the losses and regrets. The regret is normalized using its standard deviation across all workers, adjusted by a small constant 𝜖: $$ \hat{R}_{ijk} = \frac{R_{ijk}}{\sigma_j(R_{ijk}) + \epsilon} $$ - Here, 𝜎𝑗 is the standard deviation of 𝑅𝑖𝑗𝑘 for a particular inference across all workers. - The small constant 𝜖 ensures numerical stability and avoids division by zero. #### Using Normalized Regrets for Weights The normalized regrets 𝑅𝑖𝑗𝑘 are then used to calculate the weights for each inference: $$ w_{ijk} = \phi'_{p,c}(\hat{R}_{ijk}) $$ These weights determine how much each raw inference 𝐼𝑖𝑗 will contribute to the final network inference. ### Forecast-Implied Inferences The Topic Coordinator takes the forecasted losses and normalized weights and produces forecast-implied inferences. A forecast-implied inference is a predicted value of a target variable that combines different forecasters' predictions and workers' inferences, where each prediction is weighted based on how accurately the forecasters predicted losses in previous time steps, or _epochs_. $$ I_{ik} = \frac{\sum_j w_{ijk} I_{ij}}{\sum_j w_{ijk}} $$ Here, 𝑤𝑖𝑗𝑘 are weights assigned to each inference based on the forecasted regret. ### Final Network Inference The final inference for the network is a weighted combination of all individual inferences following a procedure similar to the generation of forecast-implied inferences discussed above, but using the actual regrets based on the losses provided by reputers instead of forecasted losses. This combined result is expected to be more accurate and reliable due to the weighting process. ![synthesis-final](https://docs.allora.network/synthesis-final.jpg) ### Multi-Label Topics Since v0.17.0, synthesis is **label-aware**. For [multi-output topics](https://docs.allora.network/operate/topics/create#topic-types-output-arity-and-labels), the process above runs independently for each label, and the result is returned as a **network inference bundle** — a set of labeled values rather than a single number. A single-output topic is simply the special case with one canonical label (`y`), so its bundle carries a single value. For **classification** topics that set `require_unity`, the per-label outputs are constrained to sum to one (within the topic's `unity_tolerance`), so the bundle represents a probability distribution across the labels. The **outlier-resistant** network inference is only computed for single-label regression topics; it is not produced for multi-label topics. --- # Consensus and Rewards Source: https://docs.allora.network/learn/consensus-and-rewards How Allora reaches consensus on CometBFT and distributes rewards across workers, reputers, topics, and validators. The Allora Network is built as a hub chain on Cosmos. Network Validators validate the chain (standard definition). Consumers pay fees in the native network token that are distributed across the supply side in return for inferences. CometBFT Proof of Stake. ## Differentiated Incentives Each network participant has a different reward mechanism to incentivize the growth and security of the network. - Workers are rewarded based on the quality of their inferences - Reputers are rewarded based on the accuracy of their evaluations and their stake in the network - Network Validators are rewarded solely based on their stake in the network - [CometBFT](https://docs.cometbft.com/v0.38/introduction/#what-is-cometbft) - Delegated Proof of Stake For workers and reputers, we'll explain how rewards are calculated for the total number of actors within each individual participant, how topic rewards are distributed between participants, and finally how total rewards are split between validators and topics. ## Worker Rewards Workers are specifically rewarded based on their unique contribution to the synthesized network inference provided by the Allora Network to a consumer. - Inference workers are scored using a one-out inference - Forecasting workers are scored using both one-out and one-in inferences Scores are used to calculate rewards. ### Inference Workers **One-out Inference**: evaluating the impact of an inference by removing one worker’s inference and seeing how much the loss increases. The performance score $$T_{ij}$$ for inference worker $$j$$ is calculated as the difference in the logarithm of losses with and without the worker’s inference. If removing a worker's contribution increases the loss, their performance score is positive, indicating a valuable contribution. $$ T_{ij} = \log \mathcal{L}_{ji}^- - \log \mathcal{L}_i $$ ### Forecast Workers #### Why One-Out Inferences Aren't Enough In forecasting tasks, multiple workers often contribute similar information. This means they can back each other up. If one worker is missing, the others can still maintain a similar level of performance because they provide overlapping information. When you remove one worker to see their impact (**one-out inference**), the overall performance might not change much because the remaining workers can cover for the missing one. This makes it hard to see the true value of the removed worker's contribution. #### Why One-In Inferences Are Needed To better understand each forecast worker's unique contribution, you need to also see what happens when you specifically include their work (**one-in inference**). By adding a worker’s forecast-implied inference to a group without any forecast-implied inferences and measuring the change, you can see how much they really help on their own. $$ T_{ik}^+ = \log \mathcal{L}_i^- - \log \mathcal{L}_{ki}^+ $$ #### Combining Both To fairly measure each forecasting worker's contribution, we combine the one-out and one-in scores. This combined score gives a balanced view of how removing or adding each forecasting worker impacts the prediction accuracy. $$ T_{ik} = (1 - f^+)T_{ik}^- + f^+T_{ik}^+ $$ - $$f+$$ is a weighting factor that adjusts the importance of the one-in score. ## Reputer Rewards Reputers are rewarded based on their accuracy relative to consensus (formed by all reputers providing data for a topic) and stake, with added functionality to prevent centralization of rewards caused by reputers with larger stakes. ### Problem: Runaway Centralization 1. **Stake-Weighted Average:** - Reputers are actors who report how accurate certain predictions or inferences are against the ground truth. - Normally, we might average the accuracy (or "losses") they report but give more weight to reputers with bigger stakes (more reputation). - This means reputers with more stake have more influence on the consensus (agreed-upon truth). 2. **Runaway Effect:** - The problem is that reputers with higher stakes will be closer to consensus, which they have more influence on, and get more rewards, which further increases their stakes. - This creates a cycle where the rich get richer, leading to centralization. A few reputers end up controlling most of the influence and rewards, which is unfair and unhealthy for the system. ### Solution: Adjusted Stake 1. **Adjusted Stake:** - To prevent runaway centralization, we adjust how much weight each reputer's stake has when setting the consensus. - Instead of using the full stake for weighting, we use an adjusted version that doesn’t let any one reputer dominate. 2. **How It Works:** - The formula for adjusted stake ensures that if a reputer's stake goes above a certain level, it doesn’t keep increasing their weight in the consensus calculation. - It levels the playing field, so reputers with smaller stakes still have some influence. $$\hat{S}_{im} = \min \left( \frac{N_r a_{im} S_{im}}{\sum_m a_{im} S_{im}}, 1 \right)$$ Where: - $$N_{r}$$​ is the number of reputers. - $$a_{im}$$ is a listening coefficient, which is a measure of how much the network considers each reputer's input, and is optimized to maximize consensus among the reputers. - $$S_{im}$$​ is the original stake. ## Topic Rewards Now that we've explained the mechanisms behind distributing rewards for the actors of each network participant, let's dive in to how topic rewards are distributed across the groups of:: - inference workers - forecast workers - reputers The common objective of the calculated reward distribution across the network is to incentivize decentralization. ### Key Factors #### Modified Entropy Entropy, in this context, is a measure of how spread out the rewards are among participants. We calculate entropy for each class of tasks (inference, forecast, reputer), which helps in determining how decentralized the reward distribution is. Higher entropy means rewards are more evenly spread out across all participants. The modified entropy for each class of tasks is given by the following equations: **Inference** $$ F_i = - \sum_j f_{ij} \ln \left( f_{ij} \left( \frac{N_i^{\text{eff}}}{N_i} \right)^\beta \right) $$ Where: - $$ F_i $$ is the entropy for inference workers. - $$ \sum_j $$ means we add up the values for all inference workers $$ j $$. - $$ f_{ij} $$ is the (smoothed) fraction of rewards for the $$ j $$-th inference worker. - $$ N_i^{\text{eff}} $$ is the effective number of inference workers (a fair count to prevent cheating). - $$ N_i $$ is the total number of inference workers. - $$ \beta $$ is a constant that helps adjust the calculation. The formula for forecast workers ($$ G_i $$) and reputers ($$ H_i $$) is similar: $$ G_i = - \sum_k f_{ik} \ln \left( f_{ik} \left( \frac{N_f^{\text{eff}}}{N_f} \right)^\beta \right) $$ $$ H_i = - \sum_m f_{im} \ln \left( f_{im} \left( \frac{N_r^{\text{eff}}}{N_r} \right)^\beta \right) $$ Where: - $$ G_i $$ and $$ H_i $$ are the entropies for forecast workers and reputers, respectively. - $$ \sum_k $$ and $$ \sum_m $$ mean we add up the values for all forecast workers $$ k $$ and all reputers $$ m $$. - $$ f_{ik} $$ and $$ f_{im} $$ are the (smoothed) fractions of rewards for the $$ k $$-th forecast worker and the $$ m $$-th reputer. - $$ N_f^{\text{eff}} $$ and $$ N_r^{\text{eff}} $$ are the effective numbers of forecast workers and reputers. - $$ N_f $$ and $$ N_r $$ are the total numbers of forecast workers and reputers. where we have defined modified reward fractions per class as: $$ f_{ij} = \frac{\tilde{u}_{ij}}{\sum_j \tilde{u}_{ij}}, \quad f_{ik} = \frac{\tilde{v}_{ik}}{\sum_k \tilde{v}_{ik}}, \quad f_{im} = \frac{\tilde{w}_{im}}{\sum_m \tilde{w}_{im}} $$ Here, the tilde over the rewards indicates they are smoothed using an exponential moving average to remove noise and volatility from the decentralization measure. #### Effective Number of Participants To prevent manipulation of the reward system against sybil attacks, we calculate the effective number of participants (actors). It ensures that the reward distribution remains fair even if someone tries to game the system. $$ N_i^{\text{eff}} = \frac{1}{\sum_j f_{ij}^2}, \quad N_f^{\text{eff}} = \frac{1}{\sum_k f_{ik}^2}, \quad N_r^{\text{eff}} = \frac{1}{\sum_m f_{im}^2} $$ Where: - $$ N_i^{\text{eff}} $$, $$ N_f^{\text{eff}} $$, and $$ N_r^{\text{eff}} $$ are the effective numbers of inference workers, forecast workers, and reputers. - The fractions $$ f_{ij} $$, $$ f_{ik} $$, and $$ f_{im} $$ are squared and then added up for each type of worker. ### Putting It All Together #### Dividing the Pie: Who Gets What? We take the total reward for a task and split it among the different worker types based on our entropy calculations. Here's the formula: $$ U_i = \frac{(1 - \chi)\gamma F_i E_{i,t}}{F_i + G_i + H_i}, \quad V_i = \frac{\chi \gamma G_i E_{i,t}}{F_i + G_i + H_i}, \quad W_i = \frac{H_i E_{i,t}}{F_i + G_i + H_i} $$ In simpler terms: - $$ U_i $$ is the reward for inference workers. - $$ V_i $$ is the reward for forecast workers. - $$ W_i $$ is the reward for reputers. - $$ E_{i,t} $$ is the total reward for the participants in topic $$ t $$. - $$ \chi $$ is a factor that adjusts how much reward goes to forecast workers. - $$ \gamma $$ is a is a normalization factor to ensure the rewards add up to $$ E_{i,t} $$. - $$ F_i $$, $$ G_i $$, and $$ H_i $$ are the entropies for inference workers, forecast workers, and reputers. #### What Value is Added by Forecasters? Checking the Predictions We quantify the value added by the entire forecasting task using a score called $$ T_i $$: $$ T_i = \log L_i^- - \log L_i $$ Where: - $$ T_i $$ is the performance score for the entire forecasting task. - $$ L_i^- $$ is the network loss without any forecast-implied inferences (the inference task alone). - $$ L_i $$ is the network loss with the forecast task included. We then use this score to decide how much the forecast workers should get. The higher their score relative to inference workers, the higher the total reward allocated to forecasters: $$ \tau_i \equiv \alpha \frac{T_i - \min(0, \max_j T_{ij})}{|\max_j T_{ij}|} + (1 - \alpha) \tau_{i-1} $$ Where: - $$ \tau_i $$ is a ratio expressing the relative added value of the forecasting task relative to inference workers. - $$ T_{ij} $$ is the performance score for each inference worker. This ratio is then mapped onto a fraction of the worker rewards that is allocated to forecasters: $$ \chi = \begin{cases} 0.1 & \text{if } \tau_i < 0, \\ 0.4 \tau_i + 0.1 & \text{if } 0 \leq \tau_i < 1, \\ 0.5 & \text{if } \tau_i \geq 1. \end{cases} $$ #### The Normalization Factor We use a normalization factor $$ \gamma $$ to ensure the rewards add up to $$ E_{i,t} $$: $$ \gamma = \frac{F_i + G_i}{(1 - \chi)F_i + \chi G_i} $$ Where: - $$ \gamma $$ ensures that the total reward allocated to workers ($$ U_{i} + V_{i} $$) remains constant after accounting for the added value of the forecasting task. By using these methods, we can ensure that rewards are spread out fairly and encourage everyone to contribute their best work. ## Total Rewards 50% of the rewards in the network go to participants providing economic security and 50% of the rewards go to intelligence contributors. - Economic Security: Validators and Reputers - Intelligence Contributors: Forecast and Inference Workers ### Total Reward Distribution #### Validator Rewards Validator rewards are divided from the total allocation of 25% based on how much **stake** a given validator has in the network comparative to the overall stake of all validators in the network. #### Topic Rewards Topic rewards for a single topic are divided from the total allocation of 75% based on how much '**weight**' the topic has. ##### Understanding Topic Weight - Weight is like a score that shows how important or valuable a topic is. - This weight is based on two things: - How much reputer stake it has - How much revenue the topic generates - The formula for calculating weight looks at both these factors equally - The weight is averaged over time to keep it stable and fair, so sudden changes don’t affect it too much. --- # Allora Tokenomics Source: https://docs.allora.network/learn/tokenomics The Allora token (ALLO) is minted by the Allora Network to facilitate the exchange of value by network participants. The Allora token (ALLO) is minted by the Allora Network to facilitate the exchange of value by network participants. ## Pay-What-You-Want (PWYW) The Allora Network incorporates a Pay-What-You-Want (PWYW) model to allow token holders the flexibility to choose the fee they pay for inferences generated by the network. This model fosters inclusivity and accessibility by enabling participants to determine the value they assign to the service. Token holders have the autonomy to decide the amount of ALLO they wish to pay for a given inference, which encourages token holders to contribute to the network's ecosystem according to their perceived value of the service. **Important Note**: If participants choose to pay **zero** fees for a particular topic, the weight of that topic tends to zero. As a result, participants within that topic **receive no rewards**, and the token emission will be redistributed over other topics. This mechanism ensures that topics with no fee payments do not sustain themselves, driving healthy competition and price discovery across the network. Flexible price discovery across topics is a less opinionated method that allows the market to reach an agreed-upon price through natural negotiation and market dynamics. ## Token Emissions ### Bitcoin-like Emission Schedule - Emissions decrease over time, similar to Bitcoin's halving events. - Creates a transparent and stable token release schedule. - Ensures continuous rewards for participants in a finite-supply framework. ### Stable APY around Token Unlocks - Maintains a stable annual percentage yield (APY) for staked tokens, even during unlock periods. - Reduces the incentive to sell large quantities of tokens during major unlocks, stabilizing token value. - Promotes long-term staking and active participation in the network by ensuring predictable returns. ## ALLO Token Utility ### Purchasing Inferences - ALLO tokens can be used to buy inferences generated by the network. - Uses a PWYW model where consumers choose the ALLO fee for an inference. ### Creating or Participating in Topics - ALLO tokens are paid for creating topics or participating in the network as a worker. - ALLO tokens can be used to pay the registration fee for workers and reputers to register to a topic. ### Staking and Delegating Stake - Reputers and network validators use ALLO tokens to stake. - Token holders can [delegate stake](https://docs.allora.network/learn/key-terms#delegated-stake) to a reputer or network validator. - Staking reputers, network validators, and delegating token holders receive rewards in ALLO. ### Reward Distribution The network uses ALLO tokens to pay out rewards to participants. Participant rewards are explained in-depth in the [Consensus Layer](https://docs.allora.network/learn/consensus-and-rewards). --- # Delegating Stake on the Allora Network Source: https://docs.allora.network/learn/staking Delegating stake on the Allora Network is a way to earn passive rewards by supporting a reputer's operations. Delegating stake on the Allora Network is a way to earn passive rewards by supporting a reputer's operations. When you delegate funds to a reputer, you enhance their stake, which improves the security of topics and increases the accuracy of loss reports. In return, you receive rewards based on the reputer's performance. ## Why Delegate Stake? - Passive Earnings: Delegators earn a portion of the rewards generated by the reputer's success. - Enhanced Security: Your stake contributes to the overall security and trustworthiness of the Allora Network. - Improved Accuracy: Higher stakes allow reputers to provide more accurate loss reports. - Withdrawal Safeguard: A withdrawal delay is in place to prevent quick attacks and ensure network stability. ## How to Delegate Stake Follow these steps to delegate your stake to a reputer node: ### Visit the Allora Explorer - Go to explorer.allora.network. ### Connect Your Wallet - Click on the "Connect Wallet" button at the top right of the page. - Choose your preferred wallet (Keplr, Leap) and connect to the network. ### Navigate to Staking - Once connected, go to the "Staking" section from the navigation menu. ### Select a Reputer - Browse the list of available reputer nodes. - Choose a reputer based on their performance metrics and reliability. ### Delegate Your Stake - Click the "Delegate" button next to the chosen reputer. - Enter the amount you want to delegate. - Confirm the transaction in your wallet. ### Monitor Your Delegation: - Track your stake and rewards over time in the explorer's dashboard. --- # Confidence Intervals Source: https://docs.allora.network/learn/confidence-intervals Confidence intervals (CIs) help users understand how much variation there is among the predictions made by different workers. Confidence intervals (CIs) help users understand how much variation there is among the predictions made by different workers. Rather than just giving one prediction number, the network also provides a **range**—a window that tells you how close or far apart the workers' predictions are. This helps gauge the **certainty** of the prediction. ## How Confidence Intervals are Generated Confidence intervals are not simply derived from the raw predictions of workers. The Allora network takes a weighted approach, accounting for the reliability of individual workers to ensure that less accurate predictions do not unduly influence the final result. Here's how the process works: 1. **Percentiles as Key Indicators**: The network uses specific percentiles to outline confidence intervals, mimicking the 1σ and 2σ limits found in a normal distribution. These include: - **2.28% and 97.72%**: Representing the extreme ends of the spectrum, these percentiles capture nearly all predictions including outliers. - **15.87% and 84.13%**: These percentiles represent a more central range, focusing on the core set of inferences with the highest levels of confidence. >While worker inferences may not follow a perfect Gaussian (bell curve) distribution, these percentiles provide a structured way to describe the uncertainty inherent in collective predictions. 2. **Weighted Worker Predictions**: Not all worker inferences are treated equally. Workers with a proven track record of accuracy are assigned higher **weights**, which amplify their influence on the final confidence interval. Conversely, less reliable workers are given lower weights to ensure that their predictions don’t artificially broaden the confidence interval. 3. **Building the Distribution**: Once the inferences are submitted, they are sorted from lowest to highest, and each worker’s weight is accumulated to create a **cumulative distribution function** (CDF), which allows the network to map how predictions are distributed across the worker base. 4. **Determining the Confidence Interval**: Using the CDF, the network calculates the prediction values that correspond to the chosen percentiles (e.g., 2.28%, 15.87%, etc.). To increase precision, the network employs **interpolation**—a method of estimating values that fall between two known data points in the sorted list. This ensures that the confidence intervals reflect the actual spread of inferences rather than approximate ranges. ## What Does This Mean for You? When you see a confidence interval in Allora, it gives you a sense of how **confident** the network is about the prediction. - A **narrow** confidence interval means the workers mostly agree on the result. - A **wider** confidence interval suggests that the workers’ predictions vary more, indicating more uncertainty in the result. By factoring in these confidence intervals, users can make more informed decisions about the consensus surrounding inferences provided for a given topic. --- # Networks Source: https://docs.allora.network/reference/networks Chain IDs, endpoints, and the currently deployed allora-chain version for each Allora network. > Chain IDs, endpoints, and the currently deployed `allora-chain` version for each Allora network. The Allora Network runs as two public networks: a **testnet** for development and integration, and the production **mainnet**. Each may run a different `allora-chain` version, which also determines the `emissions` REST/gRPC API version (for example, mainnet's v0.16.0 serves `emissions/v9` while testnet's v0.17.0 serves `emissions/v10`). | | Testnet | Mainnet | | --- | --- | --- | | **Chain ID** | `allora-testnet-1` | `allora-mainnet-1` | | **Deployed version** | v0.17.0 | v0.16.0 | | **Emissions API namespace** | `emissions/v10` | `emissions/v9` | | **RPC JSON** | `https://allora-rpc.testnet.allora.network/` | `https://allora-rpc.mainnet.allora.network/` | | **gRPC** | `https://allora-grpc.testnet.allora.network/` | `https://allora-grpc.mainnet.allora.network/` | | **API (Cosmos LCD - REST)** | `https://allora-api.testnet.allora.network/` | `https://allora-api.mainnet.allora.network/` | | **Explorer** | `https://explorer.testnet.allora.network/allora-testnet-1` | `https://explorer.allora.network/` | | **Faucet** | `https://faucet.testnet.allora.network/` | — | The tables on this page are rendered from a machine-readable manifest served at `/api/networks.json`. Agents and scripts can read the same chain IDs, endpoints, and versions from there instead of scraping this page. Deployed versions change with each [software upgrade](https://docs.allora.network/operate/validators/software-upgrades). Testnet is typically upgraded ahead of mainnet, so features from a newer release (such as the v0.17.0 multi-label and labeled network-inference APIs) may be available on testnet before they reach mainnet. Always confirm against the [allora-chain releases](https://github.com/allora-network/allora-chain/releases) and the [Release Notes](https://docs.allora.network/reference/release-notes). ## Testnet - **Chain ID**: `allora-testnet-1` - **Deployed version**: v0.17.0 - **Emissions API namespace**: `emissions/v10` - **RPC JSON**: `https://allora-rpc.testnet.allora.network/` - **gRPC**: `https://allora-grpc.testnet.allora.network/` - **API (Cosmos LCD - REST)**: `https://allora-api.testnet.allora.network/` - **Explorer**: `https://explorer.testnet.allora.network/allora-testnet-1` - **Faucet**: `https://faucet.testnet.allora.network/` Use the testnet for building and testing integrations, running workers/reputers, and trying features before they ship to mainnet. For wallet creation and faucet funding, see [Setup Wallet](https://docs.allora.network/get-started/setup-wallet). ## Mainnet - **Chain ID**: `allora-mainnet-1` - **Deployed version**: v0.16.0 - **Emissions API namespace**: `emissions/v9` - **RPC JSON**: `https://allora-rpc.mainnet.allora.network/` - **gRPC**: `https://allora-grpc.mainnet.allora.network/` - **API (Cosmos LCD - REST)**: `https://allora-api.mainnet.allora.network/` - **Explorer**: `https://explorer.allora.network/` - **Faucet**: — Mainnet has no faucet — fund addresses with ALLO yourself. The `emissions` API version differs by network. On mainnet (v0.16.0) network-inference endpoints live under `emissions/v9` and return a single (unlabeled) value; on testnet (v0.17.0) they live under `emissions/v10` and return [labeled network-inference bundles](https://docs.allora.network/consume/api). Pick the version segment that matches the network you are querying. ## Related - [Allora API Endpoint](https://docs.allora.network/consume/api) — querying inferences over REST - [RPC JSON Data Access](https://docs.allora.network/consume/rpc-grpc) — querying over RPC JSON - [Setup Wallet](https://docs.allora.network/get-started/setup-wallet) — RPC JSON URL and Chain ID configuration - [Software Upgrades](https://docs.allora.network/operate/validators/software-upgrades) — how network versions are upgraded --- # allorad Reference Source: https://docs.allora.network/reference/allorad Reference for allorad query and transaction commands to read from and write to the Allora chain. `allorad` commands below are broken out into: 1. [Query functions](#query-functions), or functions that read from the chain - e.g. get active topics, get amount of stake in a topic 2. [Tx functions](#tx-functions), or functions that write to the chain - e.g. create a topic, add stake to a reputer ## Query Functions These functions read from the appchain only and do not write. Add the **Command** value into your query to retrieve the expected data. ```bash allorad q emissions [Command] --node ``` ### Params - **RPC Method:** `GetParams` - **Command:** `params` - **Description:** Get the current module parameters. ### Get Next Topic ID - **RPC Method:** `GetNextTopicId` - **Command:** `next-topic-id` - **Description:** Get next topic id. Topic ids are incremented with each newly added topic. ### Get Topic - **RPC Method:** `GetTopic` - **Command:** `topic [topic_id]` - **Description:** Get topic by topic_id. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Topic Exists - **RPC Method:** `TopicExists` - **Command:** `topic-exists [topic_id]` - **Description:** True if topic exists at given id, else false. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Active Topics At Block - **RPC Method:** `GetActiveTopicsAtBlock` - **Command:** `active-topics-at-block [block_height]` - **Description:** Get the topics that were active at a given block height. - **Positional Arguments:** - `block_height` Block height to query. ### Is Topic Active - **RPC Method:** `IsTopicActive` - **Command:** `is-topic-active [topic_id]` - **Description:** True if the topic is active, else false. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Delegate Reward Per Share - **RPC Method:** `GetDelegateRewardPerShare` - **Command:** `delegate-reward-per-share [topic_id] [reputer_address]` - **Description:** Get total delegate reward per share stake in a reputer for a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `reputer_address` Address of the reputer. ### Get Delegate Stake Placement - **RPC Method:** `GetDelegateStakePlacement` - **Command:** `delegate-stake-placement [topic_id] [delegator] [target]` - **Description:** Get the amount of token delegated to a target by a delegator in a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `delegator` Address of the delegator. - `target` Address of the target. ### Get Delegate Stake Removal - **RPC Method:** `GetDelegateStakeRemoval` - **Command:** `delegate-stake-removal [block_height] [topic_id] [delegator] [reputer]` - **Description:** Get the current state of a pending delegate stake removal. - **Positional Arguments:** - `block_height` Block height to query. - `topic_id` Identifier of the topic whose information will be returned. - `delegator` Address of the delegator. - `reputer` Address of the reputer. ### Get Delegate Stake Upon Reputer - **RPC Method:** `GetDelegateStakeUponReputer` - **Command:** `delegate-stake-on-reputer [topic_id] [target]` - **Description:** Get the total amount of token delegated to a target reputer in a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `target` Address of the target reputer. ### Get Forecast Scores Until Block - **RPC Method:** `GetForecastScoresUntilBlock` - **Command:** `forecast-scores-until-block [topic_id] [block_height]` - **Description:** Get all saved scores for all forecasters for a topic descending until a given past block height. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Get Forecaster Network Regret - **RPC Method:** `GetForecasterNetworkRegret` - **Command:** `forecaster-regret [topic_id] [worker]` - **Description:** Get current network regret for a given forecaster. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `worker` Address of the forecaster. ### Get Inference Scores Until Block - **RPC Method:** `GetInferenceScoresUntilBlock` - **Command:** `inference-scores-until-block [topic_id] [block_height]` - **Description:** Get all saved scores for all inferers for a topic descending until a given past block height. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Get Inferer Network Regret - **RPC Method:** `GetInfererNetworkRegret` - **Command:** `inferer-regret [topic_id] [actor_id]` - **Description:** Get current network regret for a given inferer. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `actor_id` Address of the inferer. ### Is Reputer Nonce Unfulfilled - **RPC Method:** `IsReputerNonceUnfulfilled` - **Command:** `reputer-nonce-unfulfilled [topic_id] [block_height]` - **Description:** True if reputer nonce is unfulfilled, else false. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Is Worker Nonce Unfulfilled - **RPC Method:** `IsWorkerNonceUnfulfilled` - **Command:** `worker-nonce-unfulfilled [topic_id] [block_height]` - **Description:** True if worker nonce is unfulfilled, else false. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Get Forecaster Score EMA - **RPC Method:** `GetForecasterScoreEma` - **Command:** `forecaster-score-ema [topic_id] [forecaster]` - **Description:** Returns the latest score for a forecaster in a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `forecaster` Address of the forecaster. ### Get Inferer Score EMA - **RPC Method:** `GetInfererScoreEma` - **Command:** `inferer-score-ema [topic_id] [inferer]` - **Description:** Returns the latest score for an inferer in a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `inferer` Address of the inferer. ### Get Reputer Score EMA - **RPC Method:** `GetReputerScoreEma` - **Command:** `reputer-score-ema [topic_id] [reputer]` - **Description:** Returns the latest score for a reputer in a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `reputer` Address of the reputer. ### Get Latest Topic Inferences - **RPC Method:** `GetLatestTopicInferences` - **Command:** `latest-topic-raw-inferences [topic_id]` - **Description:** Returns the latest round of raw inferences from workers for a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Listening Coefficient - **RPC Method:** `GetListeningCoefficient` - **Command:** `listening-coefficient [topic_id] [reputer]` - **Description:** Returns the current listening coefficient for a given reputer. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `reputer` Address of the reputer. ### Get One In Forecaster Network Regret - **RPC Method:** `GetOneInForecasterNetworkRegret` - **Command:** `one-in-forecaster-regret [topic_id] [forecaster] [inferer]` - **Description:** Returns regret born from including a forecaster's implied inference in a batch with an inferer. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `forecaster` Address of the forecaster. - `inferer` Address of the inferer. ### Get Naive Inferer Network Regret - **RPC Method:** `GetNaiveInfererNetworkRegret` - **Command:** `naive-inferer-network-regret [topic_id] [inferer]` - **Description:** Returns regret born from including an inferer's naive inference in a batch. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `inferer` Address of the inferer. ### Get One Out Inferer Inferer Network Regret - **RPC Method:** `GetOneOutInfererInfererNetworkRegret` - **Command:** `one-out-inferer-inferer-network-regret [topic_id] [one_out_inferer] [inferer]` - **Description:** Returns regret born from including one inferer's implied inference in a batch with another inferer. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `one_out_inferer` Address of the inferer being compared. - `inferer` Address of the primary inferer. ### Get One Out Inferer Forecaster Network Regret - **RPC Method:** `GetOneOutInfererForecasterNetworkRegret` - **Command:** `one-out-inferer-forecaster-network-regret [topic_id] [one_out_inferer] [forecaster]` - **Description:** Returns regret born from including one inferer's implied inference in a batch with a forecaster. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `one_out_inferer` Address of the inferer. - `forecaster` Address of the forecaster. ### Get One Out Forecaster Inferer Network Regret - **RPC Method:** `GetOneOutForecasterInfererNetworkRegret` - **Command:** `one-out-forecaster-inferer-network-regret [topic_id] [one_out_forecaster] [inferer]` - **Description:** Returns regret born from including one forecaster's implied inference in a batch with an inferer. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `one_out_forecaster` Address of the forecaster. - `inferer` Address of the inferer. ### Get One Out Forecaster Forecaster Network Regret - **RPC Method:** `GetOneOutForecasterForecasterNetworkRegret` - **Command:** `one-out-forecaster-forecaster-network-regret [topic_id] [one_out_forecaster] [forecaster]` - **Description:** Returns regret born from including one forecaster's implied inference in a batch with another forecaster. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `one_out_forecaster` Address of the forecaster being compared. - `forecaster` Address of the primary forecaster. ### Get Previous Forecast Reward Fraction - **RPC Method:** `GetPreviousForecastRewardFraction` - **Command:** `previous-forecaster-reward-fraction [topic_id] [worker]` - **Description:** Return previous reward fraction for a worker. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `worker` Address of the worker. ### Get Previous Inference Reward Fraction - **RPC Method:** `GetPreviousInferenceRewardFraction` - **Command:** `previous-inference-reward-fraction [topic_id] [worker]` - **Description:** Return previous reward fraction for a worker. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `worker` Address of the worker. ### Get Previous Percentage Reward To Staked Reputers - **RPC Method:** `GetPreviousPercentageRewardToStakedReputers` - **Command:** `previous-percentage-reputer-reward` - **Description:** Return the previous percentage reward paid to staked reputers. ### Get Previous Reputer Reward Fraction - **RPC Method:** `GetPreviousReputerRewardFraction` - **Command:** `previous-reputer-reward-fraction [topic_id] [reputer]` - **Description:** Return the previous reward fraction for a reputer. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `reputer` Address of the reputer. ### Get Previous Topic Weight - **RPC Method:** `GetPreviousTopicWeight` - **Command:** `previous-topic-weight [topic_id]` - **Description:** Return the previous topic weight. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Reputer Loss Bundles At Block - **RPC Method:** `GetReputerLossBundlesAtBlock` - **Command:** `reputer-loss-bundle [topic_id] [block_height]` - **Description:** Return the reputer loss bundle at a block height. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Get Reputers Scores At Block - **RPC Method:** `GetReputersScoresAtBlock` - **Command:** `reputer-scores-at-block [topic_id] [block_height]` - **Description:** Return reputer scores at a block height. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Get Stake Removal For Reputer And Topic Id - **RPC Method:** `GetStakeRemovalForReputerAndTopicId` - **Command:** `stake-removal [reputer] [topic_id]` - **Description:** Return stake removal information for a reputer in a topic. - **Positional Arguments:** - `reputer` Address of the reputer. - `topic_id` Identifier of the topic whose information will be returned. ### Get Stake Reputer Authority - **RPC Method:** `GetStakeReputerAuthority` - **Command:** `reputer-authority [topic_id] [reputer]` - **Description:** Return total stake on reputer in a topic, including delegate stake and their own. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `reputer` Address of the reputer. ### Get Topic Fee Revenue - **RPC Method:** `GetTopicFeeRevenue` - **Command:** `topic-fee-revenue [topic_id]` - **Description:** Return effective fee revenue for a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Topic Reward Nonce - **RPC Method:** `GetTopicRewardNonce` - **Command:** `topic-reward-nonce [topic_id]` - **Description:** Return the reward nonce for a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Topic Stake - **RPC Method:** `GetTopicStake` - **Command:** `topic-stake [topic_id]` - **Description:** Return total stake in a topic, including delegate stake. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Total Reward To Distribute - **RPC Method:** `GetTotalRewardToDistribute` - **Command:** `total-rewards` - **Description:** Return total rewards to be distributed among all rewardable topics. ### Get Unfulfilled Reputer Nonces - **RPC Method:** `GetUnfulfilledReputerNonces` - **Command:** `unfulfilled-reputer-nonces [topic_id]` - **Description:** Return topic reputer nonces that have yet to be fulfilled. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Unfulfilled Worker Nonces - **RPC Method:** `GetUnfulfilledWorkerNonces` - **Command:** `unfulfilled-worker-nonces [topic_id]` - **Description:** Return topic worker nonces that have yet to be fulfilled. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Worker Forecast Scores At Block - **RPC Method:** `GetWorkerForecastScoresAtBlock` - **Command:** `forecast-scores [topic_id] [block_height]` - **Description:** Return scores for a worker at a block height. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Get Worker Inference Scores At Block - **RPC Method:** `GetWorkerInferenceScoresAtBlock` - **Command:** `inference-scores [topic_id] [block_height]` - **Description:** Return scores for a worker at a block height. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. - `block_height` Block height to query. ### Get Stake From Reputer In Topic In Self - **RPC Method:** `GetStakeFromReputerInTopicInSelf` - **Command:** `stake-reputer-in-topic-self [reputer_address] [topic_id]` - **Description:** Get the stake of a reputer in a topic that they put on themselves. - **Positional Arguments:** - `reputer_address` Address of the reputer. - `topic_id` Identifier of the topic whose information will be returned. ### Get Stake Removals Up Until Block - **RPC Method:** `GetStakeRemovalsUpUntilBlock` - **Command:** `stake-removals-up-until-block [block_height]` - **Description:** Get all pending stake removal requests going to happen at a given block height. - **Positional Arguments:** - `block_height` Block height to query. ### Get Delegate Stake Removals Up Until Block - **RPC Method:** `GetDelegateStakeRemovalsUpUntilBlock` - **Command:** `delegate-stake-removals-up-until-block [block_height]` - **Description:** Get all pending delegate stake removal requests going to happen at a given block height. - **Positional Arguments:** - `block_height` Block height to query. ### Get Stake Removal Info - **RPC Method:** `GetStakeRemovalInfo` - **Command:** `stake-removal-info [address] [topic_id]` - **Description:** Get a pending stake removal for a reputer in a topic. - **Positional Arguments:** - `address` Address of the reputer. - `topic_id` Identifier of the topic whose information will be returned. ### Get Delegate Stake Removal Info - **RPC Method:** `GetDelegateStakeRemovalInfo` - **Command:** `delegate-stake-removal-info [delegator] [reputer] [topic_id]` - **Description:** Get a pending delegate stake removal for a delegator in a topic. - **Positional Arguments:** - `delegator` Address of the delegator. - `reputer` Address of the reputer. - `topic_id` Identifier of the topic whose information will be returned. ### Get Topic Last Worker Commit Info - **RPC Method:** `GetTopicLastWorkerCommitInfo` - **Command:** `topic-last-worker-commit [topic_id]` - **Description:** Get the last commit by a worker for a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Topic Last Reputer Commit Info - **RPC Method:** `GetTopicLastReputerCommitInfo` - **Command:** `topic-last-reputer-commit [topic_id]` - **Description:** Get the last commit by a reputer for a topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned. ### Get Forecasts for a Topic at Block Height - **RPC Method:** `GetForecastsAtBlock` - **Command:** `forecasts-at-block [topic_id] [block_height]` - **Description:** Get the Forecasts for a topic at block height. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned - `block_height` Number of blocks that precede the specific block you are trying to query ### Get Multiple Reputer Stakes in a Topic - **RPC Method:** `GetMultiReputerStakeInTopic` - **Command:** `multi-reputer-stake [addresses] [topic_id]` - **Description:** Returns the stake for each reputer in a given list. The list can be up to `max_page_limit` in length; reputers with no stake default to 0. - **Positional Arguments:** - `addresses` List of reputer addresses - `topic_id` Identifier of the topic whose information will be returned ### Get All Inferences Produced for a Topic in a Particular Timestamp - **RPC Method:** `GetInferencesAtBlock` - **Command:** `inferences-at-block [topic_id] [block_height]` - **Description:** Get All Inferences produced for a topic in a particular timestamp. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned - `block_height` Number of blocks that precede the specific block you are trying to query ### Check if Reputer is Registered in the Topic - **RPC Method:** `IsReputerRegisteredInTopicId` - **Command:** `is-reputer-registered [topic_id] [address]` - **Description:** True if reputer is registered in the topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned - `address` Reputer Address ### Check if an Address is a Whitelist Admin - **RPC Method:** `IsWhitelistAdmin` - **Command:** `is-whitelist-admin [address]` - **Description:** Check if an address is a whitelist admin. True if so, else false. - **Positional Arguments:** - `address` Address to check ### Check if Worker is Registered in the Topic - **RPC Method:** `IsWorkerRegisteredInTopicId` - **Command:** `is-worker-registered [topic_id] [address]` - **Description:** True if worker is registered in the topic. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned - `address` Address to check ### Get the Latest Network Inferences and Weights for a Topic - **RPC Method:** `GetLatestNetworkInferences` - **Command:** `latest-network-inferences [topic_id]` - **Description:** Get the latest Network inferences and weights for a topic. Returns whatever information it has available. An outlier-resistant variant is available as `GetLatestNetworkInferencesOutlierResistant` (`latest-network-inferences-outlier-resistant [topic_id]`). - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned ### Get the Network Inferences for a Topic at a Block Height - **RPC Method:** `GetNetworkInferencesAtBlock` - **Command:** `network-inferences-at-block [topic_id] [block_height_last_inference]` - **Description:** Get the Network Inferences for a topic at a block height where the last inference was made. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned - `block_height_last_inference` Block height where the last inference was made ### Get the Network Loss Bundle for a Topic at Given Block Height - **RPC Method:** `GetNetworkLossBundleAtBlock` - **Command:** `network-loss-bundle-at-block [topic_id] [block]` - **Description:** Get the network loss bundle for a topic at given block height. - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned - `block` Block to query on ### Get Amount of Stake in a Topic for a Delegator - **RPC Method:** `GetStakeFromDelegatorInTopic` - **Command:** `stake-delegator-in-topic [delegator_address] [topic_id]` - **Description:** Get amount of stake in a topic for a delegator. - **Positional Arguments:** - `delegator_address` Address of the delegator - `topic_id` Identifier of the topic whose information will be returned ### Get Amount of Stake from Delegator in a Topic for a Reputer - **RPC Method:** `GetStakeFromDelegatorInTopicInReputer` - **Command:** `stake-delegator-in-topic-reputer [delegator_address] [reputer_address] [topic_id]` - **Description:** Get amount of stake from delegator in a topic for a reputer. - **Positional Arguments:** - `delegator_address` Address of the delegator - `reputer_address` Address of the reputer - `topic_id` Identifier of the topic whose information will be returned ### Get Reputer Stake in a Topic - **RPC Method:** `GetReputerStakeInTopic` - **Command:** `stake-in-topic-reputer [address] [topic_id]` - **Description:** Get reputer stake in a topic, including stake delegated to them in that topic. - **Positional Arguments:** - `address` Address of the reputer - `topic_id` Identifier of the topic whose information will be returned ### Get Total Delegate Stake in a Topic and Reputer - **RPC Method:** `GetDelegateStakeInTopicInReputer` - **Command:** `stake-total-delegated-in-topic-reputer [reputer_address] [topic_id]` - **Description:** Get total delegate stake in a topic and reputer. - **Positional Arguments:** - `reputer_address` Address of the reputer - `topic_id` Identifier of the topic whose information will be returned ### Get the Total Amount of Staked Tokens by All Participants in the Network - **RPC Method:** `GetTotalStake` - **Command:** `total-stake` - **Description:** Get the total amount of staked tokens by all participants in the network. ### Get the Latest Inference for a Given Worker and Topic - **RPC Method:** `GetWorkerLatestInputInferenceByTopicId` - **Command:** `latest-input-inference [topic_id] [worker_address]` - **Description:** Get the latest inference submitted by a given worker for a topic. Returns an `InputInference` (the worker's submitted payload, including its labeled `values`). - **Positional Arguments:** - `topic_id` Identifier of the topic whose information will be returned - `worker_address` Given worker to query on In v0.17.0 this query was renamed from `GetWorkerLatestInferenceByTopicId` (`worker-latest-inference`) to `GetWorkerLatestInputInferenceByTopicId` (`latest-input-inference`), and now returns an `InputInference` instead of a dense `Inference`. The REST path is `/emissions/v10/topics/{topic_id}/workers/{worker_address}/latest_input_inference`. ## Tx Functions These functions write to the appchain. Add the **Command** value into your query to retrieve the expected data. ```bash allorad tx emissions [Command] ``` ### Create New Topic - **RPC Method:** `CreateNewTopic` - **Command:** `create-topic [creator] [metadata] [loss_method] [epoch_length] [ground_truth_lag] [worker_submission_window] [p_norm] [alpha_regret] [allow_negative] [epsilon] [merit_sortition_alpha] [active_inferer_quantile] [active_forecaster_quantile] [active_reputer_quantile] [enable_worker_whitelist] [enable_reputer_whitelist] [c_norm] [topic_type] [output_arity] [require_unity] [unity_tolerance] [max_labels_per_submission] [label_whitelist] [label_default_value] [label_case_sensitive]` - **Description:** Add a new topic to the network. - **Positional Arguments:** - `creator` The creator is the owner of the topic that is able to update the topic in the future - `metadata` - `loss_method` - `epoch_length` - `ground_truth_lag` - `worker_submission_window` - `p_norm` - `alpha_regret` - `allow_negative` - `epsilon` - `merit_sortition_alpha` - `active_inferer_quantile` - `active_forecaster_quantile` - `active_reputer_quantile` - `enable_worker_whitelist` - `enable_reputer_whitelist` - `c_norm` - `topic_type` — `1` = regression, `2` = classification - `output_arity` — `1` = single output, `2` = multiple labeled outputs - `require_unity` — classification only: require per-label outputs to sum to one - `unity_tolerance` - `max_labels_per_submission` - `label_whitelist` — JSON array of permitted labels; `'[]'` means unrestricted - `label_default_value` - `label_case_sensitive` — immutable after creation Detailed instructions on [how to create a topic](https://docs.allora.network/operate/topics/create) are linked. ### Update Topic - **RPC Method:** `UpdateTopic` - **Command:** `update-topic [sender] [topic_id] [metadata] [loss_method] [alpha_regret] [merit_sortition_alpha] [p_norm] [c_norm] [max_labels_per_submission] [label_whitelist] [label_default_value]` - **Description:** Update an existing topic's modifiable configuration. Only the topic creator may do so. `topic_type`, `output_arity`, `require_unity` and `label_case_sensitive` are fixed at creation. - **Positional Arguments:** - `sender` Must be the topic creator - `topic_id` - `metadata` - `loss_method` - `alpha_regret` - `merit_sortition_alpha` - `p_norm` - `c_norm` - `max_labels_per_submission` - `label_whitelist` — full replacement; an empty list sets the topic to unrestricted - `label_default_value` `update-topic` performs a **full replacement** of the fields it accepts. In particular, sending an empty `label_whitelist` sets the topic to *unrestricted* rather than preserving the current list. Label changes are rejected while a worker submission window is open for the topic. ### Add an Admin Address to the Whitelist - **RPC Method:** `AddToWhitelistAdmin` - **Command:** `add-to-whitelist-admin [sender] [address]` - **Description:** Add an admin address to the whitelist used for admin functions on-chain. - **Positional Arguments:** - `sender` Address of the sender - `address` Address that will be added to the whitelist ### Remove an Admin Address from the Whitelist - **RPC Method:** `RemoveFromWhitelistAdmin` - **Command:** `remove-from-whitelist-admin [sender] [address]` - **Description:** Remove an admin address from the whitelist used for admin functions on-chain. - **Positional Arguments:** - `sender` Address of the sender - `address` Address that will be removed to the whitelist ### Register Network Actor - **RPC Method:** `Register` - **Command:** `register [sender] [topic_id] [owner] [is_reputer]` - **Description:** Register a new reputer or worker for a topic. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `topic_id` Identifier of the topic to register in - `owner` Address that will receive the actor's payouts - `is_reputer` Set to `true` to register as a reputer, `false` for a worker ### Remove a Reputer or Worker from a Topic - **RPC Method:** `RemoveRegistration` - **Command:** `remove-registration [sender] [topic_id] [is_reputer]` - **Description:** Remove a reputer or worker from a topic. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `topic_id` Identifier of the topic to deregister from - `is_reputer` Set to `true` if the network participant to remove is a reputer ### Insert Reputer Payload - **RPC Method:** `InsertReputerPayload` - **Command:** `insert-reputer-payload [sender] [reputer_data]` - **Description:** Insert reputer payload. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `reputer_data` Reputer payload to insert ### Insert Worker Payload - **RPC Method:** `InsertWorkerPayload` - **Command:** `insert-worker-payload [sender] [worker_data]` - **Description:** Insert worker payload. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `worker_data` Worker payload to insert ### Add Stake - **RPC Method:** `AddStake` - **Command:** `add-stake [sender] [topic_id] [amount]` - **Description:** Add stake [amount] to one's self sender [reputer or worker] for a topic. - **Positional Arguments:** - `sender` The staker. This is the address of the transaction sender. - `topic_id` Identifier of the topic to add stake to - `amount` The stake ### Remove Stake from a Topic - **RPC Method:** `RemoveStake` - **Command:** `remove-stake [sender] [topic_id] [amount]` - **Description:** Modify sender's [reputer] stake position by removing [amount] stake from a topic [topic_id]. - **Positional Arguments:** - `sender` The staker. This is the address of the transaction sender. - `topic_id` Identifier of the topic to remove stake from - `amount` The amount staked ### Delegate Stake to a Reputer for a Topic - **RPC Method:** `DelegateStake` - **Command:** `delegate-stake [sender] [topic_id] [reputer] [amount]` - **Description:** Delegate stake [amount] to a reputer for a topic. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `topic_id` Identifier of the topic to add stake to - `reputer` Address of the reputer - `amount` The amount to add to stake ### Remove Delegate Stake from a Topic - **RPC Method:** `RemoveDelegateStake` - **Command:** `remove-delegate-stake [sender] [topic_id] [reputer] [amount]` - **Description:** Modify sender's [reputer] delegate stake position by removing [amount] stake from a topic [topic_id] from a reputer [reputer]. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `topic_id` Identifier of the topic to remove stake from - `reputer` Address of the reputer - `amount` The amount to remove from stake ### Cancel Removing Delegate Stake - **RPC Method:** `CancelRemoveDelegateStake` - **Command:** `cancel-remove-delegate-stake [sender] [topic_id] [delegator] [reputer]` - **Description:** Cancel the removal of delegated stake for a delegator staking on a reputer in a topic - **Positional Arguments:** - `sender` This is the address of the transaction sender - `topic_id` Identifier of the topic - `delegator` Address of the delegator - `reputer` Address of the reputer ### Cancel Removing Stake - **RPC Method:** `CancelRemoveStake` - **Command:** `cancel-remove-stake [sender] [topic_id]` - **Description:** Cancel the removal of stake for a reputer in a topic - **Positional Arguments:** - `sender` This is the address of the transaction sender - `topic_id` Identifier of the topic ### Send Funds to a Topic to Pay for Inferences - **RPC Method:** `FundTopic` - **Command:** `fund-topic [sender] [topic_id] [amount]` - **Description:** Send funds to a topic to pay for inferences. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `topic_id` Identifier of the topic - `amount` The amount to send ### Get Reward for Delegator for a Topic - **RPC Method:** `RewardDelegateStake` - **Command:** `reward-delegate-stake [sender] [topic_id] [reputer]` - **Description:** Get Reward for Delegator [sender] for a topic. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `topic_id` Identifier of the topic - `reputer` Address of the reputer ### Update Network Parameters - **RPC Method:** `UpdateParams` - **Command:** `update-params [sender] [params]` - **Description:** Update parameters of the network. - **Positional Arguments:** - `sender` This is the address of the transaction sender - `params` Params to be updated --- # Allora Module Accounts Source: https://docs.allora.network/reference/module-accounts The Allora Chain uses Cosmos SDK module accounts to hold tokens belonging to various different actors on the network. The Allora Chain uses [Cosmos SDK module accounts](https://docs.cosmos.network/sdk/v0.50/build/modules/bank#module-accounts) to hold tokens belonging to various different actors on the network. This page describes the various places where module accounts hold funds, and the flow of money through the network. ### Actors that Earn Token Rewards There are three actors in the Allora network that earn token rewards: - **Cosmos Validators**: For the service of running the cosmos blockchain powering Allora. - **Reputers**: For providing ground truth to each topic, and maintaining a reputation system scoring the quality of worker outputs. - **Workers**: For creating the actual AI/ML Inferences that the system provides for each topic. ### Sources of Token Rewards There are also three sources of token rewards, that pay the three actors who earn them: - **Cosmos network transaction fees**: Transaction fees on Allora are optional, at least at the time of this writing. However Cosmos SDK does support an optional transaction fee to be paid by the creator of a transaction, paid in units of computational steps taken (like gas for those familiar with the EVM). If the creator of a transaction chooses to add a fee (say, to get a higher priority for being added to a block), that fee will be paid out as token rewards. - **Inference request fees**: When making an inference request, the requestor (inference data consumer) will bid a price they are willing to pay for that request. In that bid, they must send that amount of tokens to the network. If and when an inference is fulfilled, the Allora network will pay out the fee collected for that request as rewards. - **Token inflationary rewards**: Allora has an inflationary token emissions schedule that halves on regular intervals, similar to Bitcoin. Newly minted tokens are paid out each block as rewards. ### Module Accounts Used by Allora The following represents the list of module accounts that are changed or important in the flow of funds across the Allora Appchain. We do not discuss the standard module accounts used in cosmos-sdk validator staking, as they are unmodified from the Cosmos SDK. Note that the actual string used for the module name is the name shown in `monospace` below: - **Mint** (`mint`): The Allora mint module account is the only account allowed to create new tokens. It creates new tokens during its `BeginBlock` according to the [Allora emission schedule](https://docs.allora.network/reference/params/mint) and then immediately sends those tokens to the Fee Collector account. - **Fee Collector** (`fee_collector`): This module account collects all transaction fees on the network (this happens in the `auth` module during transaction execution). - **Distribution** (`distribution`): The distribution module holds the tokens and does the balance accounting for cosmos validator staking. It takes funds from the fee collector account. Cosmos validators can withdraw their staked tokens and receive validator rewards from this module's RPC functions. The Allora codebase does not change this standard cosmos module, but we do frontrun it (described below). - **Allora Rewards** (`allorarewards`): The Allora Rewards module account holds the tokens earned by reputers and workers for their services to the network. Reputers and workers share the collected transaction fees and inflationary rewards on the network with cosmos validators at a [percentage rate](https://docs.allora.network/reference/params/chain#percent_rewards_reputers_workers) set in the chain parameters. When rewards are paid out each block, the Allora Rewards module account pays the Allora Staking module, which then also increments the reputer or worker's stake appropriately. - **Allora Staking** (`allorastaking`): Separate from the standard cosmos validator staking modules and workflow, Allora supports staking for our Reputer and Workers actor roles. The Allora Staking module account is our analog to the distribution module. It holds the tokens that stakers send to the network when they deposit stake, and it also holds the rewards that stakers receive from transaction fees, newly minted token inflation, and inference request fees. When reputers or workers go to withdraw their stake, the rewards are automatically combined with their stake and automatically claimed. - **Allora Requests** (`allorarequests`) — *historical*: this account held the tokens paid by Inference Consumers when they made an inference request, escrowing funds for a subscription and paying out to the Fee Collector only as inferences were made against it. It belongs to the early inference-request model; current releases do not define it, declaring `allorastaking`, `allorarewards` and `allorapendingrewards` instead. ### Module Execution Order in a Block and the Impact on Payment Flows In Cosmos SDK, before the transactions of a block are processed, modules are able to specify `BeginBlock` and `EndBlock` functions that run at the beginning and end of a block, respectively. Below you can see a snippet from Allora Chain's app.yaml file, which specifies the order that these functions should be run: ```yaml app.yaml begin_blockers: [emissions, distribution, staking, mint] end_blockers: [staking, emissions] ``` The Cosmos SDK distribution module works by implementing a `BeginBlock` function that takes the money deposited in the Fee Collector account from the _previous block_. After that, the Mint module mints new tokens to the Fee Collector account. In the middle, transactions run, and pay their transaction fees, as well as inference request fees to the Fee Collector account. The app.yaml places the Allora emissions module in front of the distribution module. This is where the `percent_rewards_reputers_workers` [chain parameter](https://docs.allora.network/reference/params/chain#percent_rewards_reputers_workers) takes some percentage of the Fee Collector's token balance, and sends it to the Allora Rewards module account. So basically, the Allora emissions module frontruns the distribution module to steal funds that it otherwise would have gotten, in order to take the percentage cut of rewards that belong to reputers and workers. ```Text Chronological Order of Payments New block starts. Call BeginBlock: BeginBlock(emissions): allorarewards takes a percentage from fee_collector BeginBlock(distribution): distribution takes all tokens left in fee_collector BeginBlock(mint): mints new tokens to fee_collector Block starts processing transactions Auth module transfers transaction fees to fee_collector for each tx Block about to end. Call EndBlock: EndBlock(emissions): all inference requests are executed, their fees are paid to fee_collector New block starts. Call BeginBlock... ``` ### Rewards Epochs Cosmos Validators can use the distribution module and staking module standard cosmos functions to manipulate their validator stake and claim their validator rewards. For Reputer and Worker rewards, the `reward_cadence` [chain parameter](https://docs.allora.network/reference/params/chain#reward_cadence) controls how often the reputer and worker rewards are paid out. Every `reward_cadence` blocks, the rewards calculation will run in the emissions `EndBlock`, which will cause the Allora Rewards module account to pay the Allora Staking module account directly. The Allora Staking module will then increase the staking balances of all actors who are paid rewards as part of this procedure. In this way Allora is able to autocompound stake positions. Finally when a Reputer or Worker wishes to withdraw their stake, they do so, and the rewards are returned together with the original balance staked by the reputer or worker in one lump sum. --- # Stake Parameters Source: https://docs.allora.network/reference/params/stake Parameters that affect both kinds of staking featured by Allora. > Parameters that affect both kinds of staking featured by Allora There are two types of staking in Allora Network which run through different staking mechanisms: Validation staking and Reputational staking. **Validation staking** comes from the popular `staking` module on Cosmos SDK. It is used when staking into Validator nodes. **Reputational staking** is specific to Allora Network, and it is used to stake into Worker and Reputer nodes. The parameters for the two types are specified below. ## Reputational Staking Parameters from the reputational-staking module on Allora Network. These are parameters for staking into reputers and workers. These parameters are defined as "Chain Parameters" and can be found [here](https://docs.allora.network/reference/params/chain). The parameters of concern to reputers in particular are: - **required_minimum_stake** - **remove_stake_delay_window** ## Validation Staking Parameters from the validator-based staking module on Allora Network. These are set per network, so testnet and mainnet do not always agree; the values below were read from `/cosmos/staking/v1beta1/params` on both networks on 2026-08-02. **unbonding_time** Sets the duration for which tokens remain bonded after initiating the unbonding process. Value: mainnet `1814400s` (21 days), testnet `86400s` (1 day) A longer unbonding time enhances security by discouraging malicious actors and stabilizes token supply dynamics, but too long a period may inconvenience users who want to unstake their tokens promptly. This setting achieves a reasonable trade-off. **max_validators** Sets the maximum number of validators allowed in the network. Value: mainnet `17`, testnet `50` It balances decentralization with network scalability. It will be regularly assessed and adjusted based on the network's growth and decentralization. **max_entries** Determines the maximum number of entries in the staking transaction pool. Value: `7` Standard value. It balances the transaction pool size based on expected network demand. It will be regularly assessed and adjusted as the network evolves. **historical_entries** Sets the maximum number of historical entries stored in the staking module. Value: `10000` Standard value. It balances historical data retention with storage efficiency. It will be regularly assessed and adjusted based on storage capabilities and network requirements. **bond_denom** Specifies the denomination of the bonded tokens. Value: `uallo` **min_commission_rate** Sets the minimum commission rate a validator can charge. Value: `0.050000000000000000` (5%) on both networks A floor on commission keeps validator operation economically viable while leaving operators free to compete above it. --- # Consensus Parameters Source: https://docs.allora.network/reference/params/consensus Parameters that uniquely affect validators of the Allora Chain. > Parameters that uniquely affect validators of the Allora Chain **block.max_bytes** Sets the maximum size of a block in bytes. Value: `22020096` Standard value. This parameter limits the block size, preventing excessive network load. However, setting it too low may restrict the number of transactions in a block. The current value strikes a balance between controlling block size and allowing for sufficient transaction throughput. **block.max_gas** Sets the maximum amount of gas that can be used in a block. Value: `-1` Standard value. The current setting allows for flexibility by indicating no limit on the maximum gas usage in a block. While this offers freedom for transactions, careful monitoring is needed to prevent potential abuse. This approach acknowledges the need for adaptability in a dynamic network environment. **evidence.max_age_num_blocks** Sets the maximum age (in blocks) of evidence that can be included in a block. Value: `100000` Standard value. By limiting the age of evidence, this parameter maintains network security by preventing the inclusion of outdated evidence. The chosen value strikes a reasonable balance between retaining relevant evidence and ensuring integrity of the network. **evidence.max_age_duration** Sets the maximum age (in nanoseconds) of evidence that can be included in a block. Value: `172800000000000` Standard value. This parameter complements `max_age_num_blocks` by providing an additional measure to limit the inclusion of outdated evidence. The current setting aligns with the need for a comprehensive yet controlled approach to evidence inclusion. **evidence.max_bytes** Sets the maximum size of evidence in bytes. Value: `1048576` Standard value. Controlling the size of evidence prevents potential abuse and ensures efficient network operation. While too low a value may restrict the inclusion of legitimate evidence, the current setting finds a suitable compromise between limiting size and maintaining the effectiveness of the evidence mechanism. **validator.pub_key_types** Specifies the supported public key types for validators. Value: `["ed25519"]` Standard value. This parameter enhances security by explicitly specifying the supported public key type for validators. --- # Mint Parameters Source: https://docs.allora.network/reference/params/mint Parameters from the minting module on Allora Network. > Parameters from the minting module on Allora Network The mint module holds the emission schedule. Query the live set at `/mint/v5/params` — see [Networks](https://docs.allora.network/reference/networks) for each network's LCD URL. ## Current Parameters Values below were read from `/mint/v5/params` on 2026-08-02 and were identical on testnet and mainnet. Descriptions are the field comments from `x/mint/proto/mint/v5/types.proto`. | Parameter | Meaning | Value | |---|---|---| | `mint_denom` | Type of coin to mint | `uallo` | | `max_supply` | Maximum total supply of the coin | `1000000000000000000000000000` (1e27 uallo = 1 billion ALLO) | | `f_emission` | Ecosystem treasury fraction ideally emitted per unit time | `0.035` | | `one_month_smoothing_degree` | One-month exponential moving average smoothing factor | `0.1` | | `ecosystem_treasury_percent_of_total_supply` | Percentage of total supply reserved and locked in the ecosystem treasury | `0.2145` | | `foundation_treasury_percent_of_total_supply` | Percentage of total supply unlocked and usable in the foundation treasury | `0.177` | | `participants_percent_of_total_supply` | Percentage of total supply unlocked and usable by participants at genesis | `0.123` | | `investors_percent_of_total_supply` | Percentage of total supply locked in the investors bucket at genesis | `0.3105` | | `investors_preseed_percent_of_total_supply` | Percentage of total supply locked in the preseed investors bucket at genesis | `0.0` | | `team_percent_of_total_supply` | Percentage of total supply locked in the team bucket at genesis | `0.175` | | `maximum_monthly_percentage_yield` | The capped maximum monthly percentage yield | `0.0095` | | `emission_enabled` | Whether the network is allowed to emit any rewards | `true` | The module also exposes the current annualised inflation at `/mint/v5/inflation` and a breakdown at `/mint/v5/emission_info`. ## Historical Parameters The mint module originally used the Cosmos SDK's inflation parameters. They are declared in allora-chain through the v0.0.x line, and no release since defines them — the current module takes the parameter set above instead. They are kept here because older material still refers to them. Values are the defaults from v0.0.10 `x/mint/types/params.go`. | Parameter | Meaning | Historical default | |---|---|---| | `inflation_rate_change` | Maximum annual change in the inflation rate | `357.3582624` | | `inflation_max` | Maximum inflation rate | `357.3582624` | | `inflation_min` | Minimum inflation rate | `0` | | `goal_bonded` | Target ratio of bonded (staked) tokens to total supply | `0.67` | | `blocks_per_year` | Blocks the inflation schedule assumes per year | `6311520` (a block every ~5 seconds) | | `halving_interval` | Block interval for halving the block reward | `25246080` | | `current_block_provision` | Initial provision minted per block | `2831000000000000000` uallo (2.831 ALLO) | --- # Chain Parameters Source: https://docs.allora.network/reference/params/chain A glossary and description of chain-level parameters. > A glossary and description of chain-level parameters ## Mint Module and Token Inflation Parameters With the exception of `max_supply`, the parameters in this section are **historical**. They are the Cosmos-style inflation parameters of the early mint module, declared in allora-chain through the v0.0.x line; no release since defines them. The current mint module takes a different parameter set entirely — `mint_denom`, `max_supply`, `f_emission`, `one_month_smoothing_degree`, the treasury/participant/investor/team percentages and `maximum_monthly_percentage_yield`. See [Mint Parameters](https://docs.allora.network/reference/params/mint) for the values the chain serves today. #### inflation_rate_change The maximum permitted annual change in the inflation rate. The mint module will throw an error if the inflation rate moves by more than this value in a year. Default Value: 357.3582624 #### inflation_max The maximum inflation rate. The mint module will throw an error if the inflation rate exceeds this value. Default Value: 357.3582624 #### inflation_min The minimum permitted inflation rate. The mint module will throw an error if the inflation rate goes below this value. Default Value: 0 #### goal_bonded The goal used to target the percentage of bonded staking cosmos validators. Default Value: 0.67 #### blocks_per_year The amount of blocks that the inflation schedule believes will happen each year. Default Value: 6311520 #### max_supply The capped amount of tokens that will ever be allowed to exist. Default Value: 1 billion ALLO \* 1e18 (for base unit uallo) = 1e27 uallo, written out as `1000000000000000000000000000` Unlike the rest of this section, `max_supply` is a current parameter: the live mint module served this same value on both testnet and mainnet when this page was last probed, on 2026-08-02. #### halving_interval The number of blocks at which to halve the inflation rate of newly minted tokens, like Bitcoin's emissions schedule. Default Value: 25246080 #### current_block_provision Number of tokens that will be minted every block during a halving interval. This chain parameter controls the first value set for the first block. Afterwards, at each halving, this value is divided by two. Default Value: 2831000000000000000 uallo per block (2.831 ALLO) ## Allora Specific Parameters Most of this section is **historical**. Of the parameters below, the live emissions module still serves only `required_minimum_stake`, `remove_stake_delay_window`, `epsilon_safe_div` and `max_string_length` (plus the multi-label parameters in the next section); the rest date from the v0.0.x line, when the network ran on repeating inference requests, and appear in no emissions parameter set from v2 onwards. Entries that the chain still defines carry a note giving the live value. Probed against the testnet LCD on 2026-08-02. #### reward_cadence The duration of a reward epoch in blocks. Every `reward_cadence` blocks, rewards are recomputed within `EndBlock`. Default Value: 600 blocks Shorter epochs can lead to more frequent reward updates and responsiveness. This is advantageous for rapidly reacting to changes in the network (eg new topics, models, incentives, etc) and make the rewards available earlier. However, small values also have an impact on network efficiency. #### min_topic_unmet_demand The minimum unmet demand on a topic to consider it active, and thus enter rounds of inference solicitation and weight adjustment. Default Value: 100 allo The value provides a minimum amount of demand in order to trigger inference and weight adjustment rounds, to protect the network against activity of little to no added value. It is also kept small enough to not represent a barrier of entry for participation. #### max_topics_per_block Maximum number of active topics to run inference and weight adjustment rounds for on each block. Default Value: 2048 topics This value is high enough to allow a reasonable number of active topics to coexist, while also protecting the network against too much activity per block, preventing congestion and ensuring a more predictable block processing time. #### min_request_unmet_demand Threshold under which the inference requests will be deleted or prevented from being created. Default Value: 1 allo The purpose is to allow to prevent unnecessary processing of requests with minimal impact, keeping the state of the chain tidy, while at the same time be conservative with partially exhausted inference requests. #### max_missing_inference_percent The percentage of inference rounds missed by a worker, over which the worker gets penalized. Default Value: 20% Penalizing workers for missing inferences encourages reliability and accountability in the AI inference process. However, setting this value too low may lead to frequent penalties, potentially discouraging worker participation. A value that strikes a balance between both has been set. #### required_minimum_stake Sets the minimum stake to be considered as a reputer in good standing. If a reputer has less than this stake, than their contribution to reputation scoring will be ignored, and they will not receive any rewards from the system. Historical default: 100 allo. **Current chain:** the testnet emissions module served `required_minimum_stake` = `100000` when this page was last probed, on 2026-08-02. Setting a minimum stake helps ensure that participants have a vested interest in the network's success and are not simply sybils, enhancing security and commitment, while at the same time not being too high so that it may limit the accessibility of the network and discourage potential legitimate participants. #### remove_stake_delay_window The delay between a staker initiating the unstaking process and their tokens actually being released. This protects against flash-type attacks. **Current chain:** the parameter is defined in **blocks**. On testnet (v0.17.0) the live value was `302400` when this page was last probed, on 2026-08-02. This is the value that governs unstaking today. **Historical default:** 86400 seconds (1 day), from the v0.0.x line, when the parameter was expressed in seconds rather than blocks. A fair delay in unstaking, which can ensure stability in the network by preventing sudden fluctuations in staked tokens and discourage malicious actors, while keeping it low enough so it is not very inconvenient to users who want to unstake their tokens promptly. #### min_request_cadence Sets the minimum allowed time interval, in seconds, between consecutive AI calls from an inference request. Default Value: 10 seconds Imposing a minimum cadence ensures a reasonable pacing of inference requests, preventing potential abuse or unnecessary strain on the network. Adjusted based on the expected frequency of AI inference requests and the network's capacity, balanced between responsiveness and resource efficiency. #### min_weight_cadence Sets the minimum allowed time interval, in seconds, between consecutive calls for topic weight adjustment. Default Value: 3600 seconds (1 hour) Imposing a minimum cadence ensures a reasonable pacing of loss-calculation, preventing potential abuse or unnecessary strain on the network. That being said, it need not occur too frequently, because weights accrue over many inferences anyway, and these calls are relatively expensive involving off-chain communication. #### max_inference_request_validity Sets the maximum allowable time, in seconds, for an AI inference request to remain valid before expiration. Default Value: 31449600 seconds (52 weeks, ~1 year) Setting a maximum validity time ensures that AI inference requests are processed within a reasonable timeframe, preventing outdated requests, while at the same time allowing inference requests to be planned and executed at the designed cadence within a generous timeframe, especially where time-dependent effects (e.g. seasonal effects) can happen. #### max_request_cadence Sets the maximum allowable time, in seconds, between consecutive AI calls from a repeating inference request — the slowest cadence a request may be scheduled at. It is the upper bound to `min_request_cadence`'s lower bound. Default Value: 31449600 seconds (52 weeks, ~1 year) Capping the cadence stops a request from spacing its inferences so far apart that it occupies the network without producing useful data. The cap is set equal to `max_inference_request_validity`, a conservative and flexible choice that lets request creators plan as far ahead as a request is allowed to remain valid. #### percent_rewards_reputers_workers Cosmos validators, Allora Reputers, and Allora Workers all deserve to be paid out rewards from token inflation as well as collected transaction fees for using the Allora network. In Allora, we have two [payment flows](https://docs.allora.network/reference/module-accounts) for paying out rewards. Cosmos validators use the standard cosmos-sdk staking flows to get their rewards, and reputers and workers separately get their rewards from the Allora specific algorithm and code. This parameter controls the ratio of rewards between cosmos validators on one side, and reputers and workers on the other. Historical default: 50%. **Current chain:** the live emissions module does not define `percent_rewards_reputers_workers`. It defines `validators_vs_allora_percent_reward`, which was `0.25` on testnet when this page was last probed, on 2026-08-02. A higher percentage would pay more transaction fees to reputers and workers, at the expense of giving less rewards to cosmos validators. A lower percentage value would give more rewards to cosmos validators, but pay out less rewards to reputers and workers for their services to the network. #### epsilon_safe_div A small tolerance quantity used to cap division by zero. Default Value: 0.0000001 #### max_string_length The maximum length of a string to allow to store on the chain. For example, used in limiting metadata for the creation of new topics. Default Value: 255 ## Multi-Label Parameters These parameters (introduced in v0.17.0) bound the size of the [label registry](https://docs.allora.network/operate/topics/create#topic-types-output-arity-and-labels) used by multi-output topics. #### max_canonical_label_byte_length The maximum byte length of a canonical label name, after NFC normalization and whitespace trimming. Default Value: 64 #### max_topic_label_whitelist_size The maximum number of canonical labels allowed in a single topic's label whitelist. Default Value: 256 #### max_epoch_label_registry_size The maximum number of labels allowed in an epoch label registry for a single (topic, nonce). Default Value: 32768 --- # llms.txt and agent endpoints Source: https://docs.allora.network/reference/llms-and-agents The machine-readable surfaces of these docs — llms.txt, llms-full.txt, per-page raw markdown under /raw/, and the JSON manifests under /api/. Everything on this site is also published in formats meant for programs rather than browsers: an index of every page, the full text of every page, the raw markdown of any single page, and JSON manifests for the facts that change without anyone editing a page. No API key and no authentication. If you are an agent working through a task rather than looking up a format, start at the [agent quickstart](https://docs.allora.network/get-started/quickstart-agents). ## At a glance | URL | What it is | Fetch it when | | --- | --- | --- | | [`/llms.txt`](https://docs.allora.network/llms.txt) | Index of every page: title, URL, one-line description | You need to route a question to the right page | | [`/llms-full.txt`](https://docs.allora.network/llms-full.txt) | Full text of every page in one file (~450 KB) | You want the whole corpus in one request | | `/raw/.md` | One page as plain markdown | You already know which page you need | | [`/api/topics.json`](https://docs.allora.network/api/topics.json) | Active topics on each network | You need live topic IDs, epochs, or loss methods | | `/api/networks.json` | Network endpoints and chain IDs | You need an RPC, LCD, or chain ID | | `/api/versions.json` | Current component versions, including the release each network runs | You need a version to install, pin, or match | ## llms.txt An [llmstxt.org](https://llmstxt.org) index. After a site summary, every page appears as a single line: ``` - [Page title](https://docs.allora.network/path): One-line description. ``` Pages are grouped under an H2 per top-level section (Get Started, Build on Allora, Consume Inference, Operate the Network, Learn, Reference) and listed in site navigation order — the same order as the sidebar. ```bash curl -s https://docs.allora.network/llms.txt ``` ## llms-full.txt The complete text of every page, concatenated in the same navigation order. Each page is introduced by a thematic break, its title as an H1, the canonical URL it came from, and its description (indented here so this example cannot be mistaken for a real page boundary — in the file itself these lines start at column 0): ``` --- # Page title Source: https://docs.allora.network/ One-line description. ...page body as markdown... ``` ```bash curl -s https://docs.allora.network/llms-full.txt ``` To recover per-page boundaries, split on lines matching `^Source: https://docs.allora.network/` — one per page, in the same order as `llms.txt`, each preceded by the page's H1. Counting them is a cheap check that you have the whole file: ```bash curl -s https://docs.allora.network/llms-full.txt | grep -c '^Source: https://docs.allora.network/' ``` Anything indented, or inside a fenced code block, is page content rather than a delimiter. If you only need one page, fetch its raw file instead. ## Raw markdown for one page Every page is also published on its own as plain markdown under `/raw/`, served as `text/markdown; charset=UTF-8`. ### URL convention Take the page's path, prefix it with `/raw/`, and append `.md`: | Page | Raw markdown | | --- | --- | | `/get-started/quickstart-worker` | `/raw/get-started/quickstart-worker.md` | | `/build/worker/sdk-py` | `/raw/build/worker/sdk-py.md` | | `/reference/params/chain` | `/raw/reference/params/chain.md` | | `/build/reputer` | `/raw/build/reputer.md` | That rule covers landing pages too: `/build/reputer` is a section landing page with `/build/reputer/build-a-reputer` and its siblings beneath it, and its raw file is still `/raw/build/reputer.md`. The one shape it does not cover is a landing page whose source file is named `index`, which keeps that name under `/raw/`. Today `/get-started` is the only one: it is at `/raw/get-started/index.md`, and `/raw/get-started.md` does not exist. So the complete two-step rule is **append `.md`; on a 404, retry with `/index.md`**: ```bash curl -sf https://docs.allora.network/raw/get-started.md || curl -s https://docs.allora.network/raw/get-started/index.md ``` The mapping is total: every page listed in `llms.txt` has exactly one raw file, and every raw file corresponds to a live page. Files belonging to renamed or removed pages are pruned at build time, so nothing stale is ever left behind under `/raw/`. ### What a raw file contains The page's YAML frontmatter verbatim, followed by the page body reduced to plain markdown: ```bash curl -s https://docs.allora.network/raw/get-started/quickstart-agents.md | head -9 ``` ``` --- title: Agent quickstart description: An operating guide for AI coding agents — load the machine-readable docs, apply the guardrails, and submit and consume a live testnet inference without human input. persona: AI coding agent verified_against: allora-sdk-py (github.com/allora-network/allora-sdk-py) on allora-testnet-1 (emissions/v10); live api.allora.network v2 responses; allora-forge-builder-kit main (2026-07-22) last_reviewed: 2026-07-30 --- # Agent quickstart ``` The frontmatter keys are the same five every page carries: `title`, `description`, `persona`, `verified_against` (what the content was checked against), and `last_reviewed` (`YYYY-MM-DD`). Five things differ from the page's MDX source, all of them so that the file stands on its own: - **Code snippets are inlined.** Many code blocks on the site pull their body from a runnable file in the repository, so the fence in the source is empty. In the raw markdown the snippet's actual contents are already there, exactly as the rendered page shows them. - **Links are absolute.** Internal links become full `https://docs.allora.network/...` URLs, because a detached `.md` file has no page to resolve `./sibling` against. - **Layout components are unwrapped.** Callouts, tabs, and card grids become their text content, and a layout component that occupies a line of its own is dropped — it has nothing but its tag. One used mid-sentence becomes markdown of the same meaning: a component wrapping code becomes a backtick code span. - **Data components are rendered.** The tables the site builds from the JSON manifests — the endpoint tables on [Networks](https://docs.allora.network/reference/networks), the topic tables on [Existing Allora Network Topics](https://docs.allora.network/build/forge/topics) — are written out as markdown tables carrying the same values, read from the same manifests at generation time. A field a manifest omits is an em dash, exactly as on the page. Fetch [`/api/networks.json`](https://docs.allora.network/api/networks.json) or [`/api/topics.json`](https://docs.allora.network/api/topics.json) if you would rather have the JSON. - **Versions are resolved, never placeheld.** Every current version in these docs comes from `/api/versions.json`, written in the source as a component or as a constant interpolated into a command. Both are replaced by the version string itself, read from that same file at generation time — so an install command in the raw markdown is copy-paste complete, and a version you read here is the version the page shows. Generation fails rather than publish an unresolved placeholder. Headings, prose, tables, and code are otherwise the page's own text, in the page's own order. No component survives as a literal tag: a component the generator does not know how to reduce stops the build, so a page cannot ship here with a piece of itself missing. ## JSON manifests Three files under `/api/` carry the facts that go stale on their own — chain state, endpoints, and versions — so you can read them instead of parsing prose. ### /api/topics.json Every topic currently **active** on each network. A nightly job queries each network's Cosmos LCD (REST) API, keeps only topics whose `is_topic_active` query returns `true`, and proposes the regenerated file for review. It is the same data the [Existing Allora Network Topics](https://docs.allora.network/build/forge/topics) page renders. ```bash curl -s https://docs.allora.network/api/topics.json ``` ```json { "generated_at": "2026-07-31T14:57:07Z", "source": "Cosmos LCD (REST) emissions API: next_topic_id, is_topic_active, topics", "networks": [ { "network": "testnet", "chain_id": "allora-testnet-1", "emissions_api": "v10", "lcd": "https://allora-api.testnet.allora.network", "active_topic_count": 39 } ], "topics": [ { "network": "testnet", "chain_id": "allora-testnet-1", "id": 1, "metadata": "ETH 10min Prediction", "epoch_length": 120, "loss_method": "mse", "category": "price", "sandbox": false } ] } ``` `epoch_length` is in blocks, `category` is `price`, `log-return`, or `volatility`, and `sandbox` marks the no-penalty onboarding topics. Topic IDs are per chain: the same prediction task has different IDs on testnet and mainnet. The `generated_at` field says when the published copy was built — read it rather than assuming a cadence, and confirm a topic against the chain before building against it: ```bash curl -s https://allora-api.testnet.allora.network/emissions/v10/is_topic_active/69 ``` ### /api/networks.json The network endpoints manifest, with one entry per network under `networks` (today `testnet` and `mainnet`). Each entry carries the chain ID, the deployed `allora-chain` release, the versioned `emissions` namespace to use in LCD and gRPC query paths, and the RPC, gRPC, LCD, explorer, and faucet URLs — `faucet` is omitted on networks that have none, so treat it as optional. It also carries `sandbox_topic_ids`, the topics on that network that need no whitelist and carry no penalty, which is the only place that list is declared: the topics job reads it from here to set the `sandbox` flag in `/api/topics.json`. The file documents its own fields in a `field_notes` object and records when it was last updated in `updated`. [Networks](https://docs.allora.network/reference/networks) is the prose reference, and its tables render from this same file. ```bash curl -s https://docs.allora.network/api/networks.json ``` ### /api/versions.json The current version of each Allora component the docs reference, so you can pin an install without scraping prose. Four version keys: `chain_testnet` and `chain_mainnet`, the `allora-chain` release each network is **running** — a deployment fact rather than something you install; `allora_sdk`, the Python SDK's release on PyPI; and `builder_kit`, the version of the Forge Builder Kit. The chain keys carry a leading `v` and the package versions do not, so add or strip it to match whatever you are pinning. A fifth key, `superseded`, is not a version: it maps each of those four keys to the values it has already moved past, appended whenever the version is bumped. Read it if you need to tell "old release of ours" from "version of something else" — a build gate uses it to fail the docs when a superseded value is still written down as a current one. Its arrays are empty until the first bump. ```bash curl -s https://docs.allora.network/api/versions.json ``` So a reader of this file should take the four top-level string values as the current versions, and `superseded` as history — not as a fifth component. ## How these files stay current `llms.txt`, `llms-full.txt`, and everything under `/raw/` are generated from the page sources on every build of the site and committed to [the docs repository](https://github.com/allora-network/docs); continuous integration fails a pull request whose generated files no longer match its pages. They therefore ship with the page edit that caused them, never behind it. The manifests under `/api/` are not tied to the page build. Each has a scheduled check behind it that opens a pull request when its upstream source moves, so a manifest is as current as the last proposal a human accepted — which is why `topics.json` publishes its own `generated_at` and `networks.json` its own `updated`. How much of each file that automation covers differs, which matters if you are reasoning about staleness. `topics.json` is regenerated in full from each network's LCD. In `networks.json`, only `abci_version` — the build string the network reports over RPC — is written automatically; the endpoints, the `emissions` namespace, and `deployed_version` are maintained by hand. In `versions.json`, only versions actually published upstream are written automatically; `chain_testnet` and `chain_mainnet` record which release a network is *running*, which no release feed can tell you, so a human confirms and applies those. Read the freshness metadata a manifest carries rather than assuming a cadence, and for anything you are about to spend gas on, confirm it against the chain. ## Related - [Agent quickstart](https://docs.allora.network/get-started/quickstart-agents) — guardrails and a runnable end-to-end task for AI coding agents. - [Networks](https://docs.allora.network/reference/networks) — chain IDs, RPC, LCD, and explorer endpoints in prose. - [Existing Allora Network Topics](https://docs.allora.network/build/forge/topics) — the topic tables rendered from `/api/topics.json`. --- # Allora Network Release Notes Source: https://docs.allora.network/reference/release-notes Release notes for Allora Network chain releases. ## v0.17.0 ### Key Features and Improvements #### Topics - **Multi-label & classification topics**: Topics can now be typed as regression or classification (`topic_type`) and emit either a single value or a vector of labeled outputs (`output_arity`). Multi-output topics carry a per-topic label registry, with an optional `label_whitelist`, a `max_labels_per_submission` cap, a `label_default_value` for sparse submissions, and an immutable `label_case_sensitive` flag. - **Classification unity constraint**: Classification topics can require their per-label outputs to sum to one (`require_unity`) within a configurable `unity_tolerance`. - **New topic & module parameters**: `create-topic`/`update-topic` accept the new label-registry fields, and three new module params bound label sizes (`max_canonical_label_byte_length`, `max_topic_label_whitelist_size`, `max_epoch_label_registry_size`). #### Network Inference - **Labeled network inferences**: Network inferences are now stored and served as a `NetworkInferenceBundle` of labeled values, supporting multi-label topics. Single-output topics use a canonical `y` label. - **Unified event**: A single `EventNetworkInferenceBundle` (with an `outlier_resistant` flag) replaces the separate network-inference and outlier-resistant events. - **Outlier-resistant scope**: Outlier-resistant network inferences are computed only for single-label regression topics; the outlier-resistant query now returns an error for multi-label topics. #### Queries and CLI (breaking) - **v10 emissions API**: Emissions queries and transactions move to the `emissions/v10` package and REST namespace. - **Worker latest-inference query renamed**: `GetWorkerLatestInferenceByTopicId` → `GetWorkerLatestInputInferenceByTopicId` (REST `.../latest_input_inference`), now returning an `InputInference`. - **Wider p_norm range**: The allowed `p_norm` range for topics was increased. ### Bug Fixes and Other Improvements - **AutoCLI**: Fixed parameter advertising, fixed dry-run and auto-gas handling, and added keyring simulation. - **Events**: Clamp `Dec` magnitudes in emissions events to keep event payloads compact. ### Upgrade - **v0.17.0 upgrade**: The `x/emissions` consensus version is bumped to 15. The migration backfills regression/single-output defaults on existing topics and converts stored network inferences to the new labeled bundle format. ## v0.16.0 ### Key Features and Improvements #### Math - **Regret normalization update**: Regret normalization now uses median absolute deviation (MAD), with adjusted quantiles. #### Maintenance - **Upgrade testing**: Improved testing for a more reliable upgrade process. #### Internal Refactor - **Keeper refactor**: a big refactor of the keeper internals. ## v0.15.0 ### Key Features and Improvements #### Scheduler and Settings - **Enforce recommended consensus settings** to increase network stability. - **x/scheduler module**: New module for task scheduling. #### Topic Management - **Topic configuration updates**: Topic creators can update certain topic config settings - **Per-topic c_norm**: c_norm is now a configurable per-topic field instead of a global parameter for better topic customization and performance. #### Queries and Ownership - **Open submission window queries**: New queries on open submission windows to improve submission window management on clients. - **Transfer ownership**: Workers can now transfer ownership of rewards. ### Bug Fixes and Other Improvements - **OOIF matrix**: Fix matrix for events with value bundle to avoid potential issues with event parsing. - **Active topic set**: Fix a theoretical active topic set issue. ### Security - **CometBFT**: Upgrade to v0.38.19. ## v0.14.0 ### Key Features and Improvements #### Mint Module - **Mint foundation coins**: Align foundation coins to the Allora Foundation account (#887). ## v0.13.0 ### Key Features and Improvements #### Tokenomics update - **Tokenomics adjustments**: Updated distribution, vesting and emission schedules. #### Security - **CometBFT update**: Upgraded the consensus engine to v0.38.19 to benefit from performance enhancements and security fixes. ## v0.12.0 ### Key Features and Improvements #### Database and Performance Enhancements - **PebbleDB Integration**: Enabled PebbleDB for improved database performance and reliability. #### Monitoring and Events - **Network Inferences Event**: New `EventNetworkInferences` event is now emitted when closing worker nonce, providing better visibility into network state changes. - **Mint Module Metrics**: Emit mint module metrics with improved naming conventions and additional monitoring capabilities. ### Bug Fixes and Other Improvements #### Reward and Stake Management - **Ecosystem Account Refunds**: System now prevents rewards accumulation on a scenario when topic is active but no work is submitted. - **Stake Management**: Topic weights are now properly updated during stake removal operations. - **Monthly Reward Calculation**: Fixed the occurrence and calculation of monthly PreviousPercentageRewardToStakedReputers. #### Math Improvements - **More Performant Math**: Improved performance of some mathematical calculations by using architecture-independent deterministic math operations. ## v0.11.0 ### Key Features and Improvements #### Bug fixes and other improvements - **Nonce Management**: Enhances the closing of worker and reputer nonces by ensuring critical cleanup operations are performed. - **Payload Validations**: Introduces new validations against payloads submitted by workers and reputers, ensuring consistent data. - **Network Losses**: Mitigate the presence of invalid loss bundles by filtering them instead of invalidating the network losses completely. ## v0.10.0 ### Key Features and Improvements #### Network Inferences - **Consistent Network Inferences**: Network Inferences are now stored onchain instead of being calculated at query time, providing consistent results and reducing query gas. - **Removed Network Inference On-chain Computations (API-Breaking Change)**: Weights and confidence intervals are no longer provided on-chain - they can be calculated offchain out of chain data. #### Stability and Security - **More Consistent Submission Window Handling**: Submission window boundaries are now applied more consistently. - **Input Layer Type-based Validation**: New input types apply validation at the type layer, improving data integrity and chain stability. - **Topic Weight Calculation**: Topic weights are now calculated more efficiently and accurately, fixing inaccuracies between topics with varying epoch lengths. - **Topic Rewards Volatility Reduction**: Topic rewards are now better adjusted to epoch-length-based cadence, reducing volatility and providing a more stable and predictable rewards distribution. #### Bug fixes and other improvements - **Security**: Fixes against potential attacks scenarios. - **Fix floating point ln calculation**: Fixing architecture-dependent ln calculation rounding issues. - **Emissions**: Preventing ecosystem rewards from being issued after supply cap is reached. - **Cosmos SDK Patch**: Update cosmos-sdk and IBC to fix ISA-2025-001 #### Efficiency improvements - **Log rework**: Fixed lazy logging resulting in a considerable reduction of computation time in some cases. - **EMA calculation improvement**: Prevent unneeded computation under some scenarios. ## v0.9.0 ### Key Features and Improvements #### Revamped Reward and Scoring Mechanism - **Scoring and Rewards Improvements**: The scoring and rewards mechanism has been revamped to be more robust and fair. - **Outlier Impact**: Outlier submissions are now naturally penalized more heavily, ensuring that the network is not affected by a small number of high-impact submissions. - **Normalized Standard deviations**: A common stddev is used for actors on each topic on inference synthesis, ensuring that the scoring is more consistent. - **Weights Transparency**: Inferer and Forecaster weights, and their respective stddevs are now stored onchain per-topic and can be queried. #### New Emitted Events - **New Events**: Latest worker weights and common stddev events are now emitted. #### Bug Fixes - **Rewards block event emission**: Reward events are now emitted on the block of their related nonce, aligned with scores and related events. ## v0.8.0 ### Key Features and Improvements #### Enhanced Reward and Scoring Systems - **Outlier Detection for Inference Submissions**: Introduced mechanisms to detect and manage outliers in inference submissions, ensuring higher accuracy and fairness in scoring. - **EMA Score Initialization**: Actors now have initialized Exponential Moving Average (EMA) scores, improving consistency and predictability in performance evaluation. - **Initial EMA Score Generation**: Enabled support for initial EMA score calculations with queries and events, further refining reward distribution. #### Advanced Governance and Role Management - **Global Roles and Bulk Operations**: Added global worker, reputer, and admin roles with bulk operation capabilities, streamlining role management and network administration. - **Emission Flag for Mint Module**: Introduced a boolean flag for enabling or disabling emissions within the Mint Module, offering greater control over network emissions. - **Sortition Penalties Based on Liveness**: Implemented penalties based on liveness metrics, promoting consistent participation and penalizing inactivity. #### Improved Developer Tooling and Migration Processes - **Fuzzer Whitelist Awareness**: Enhanced the fuzzer to be whitelist-aware, ensuring more targeted and reliable testing scenarios. - **Install Script Improvements**: Updated the install script to handle release asset naming conventions, simplifying developer setup for new releases. - **Backward Compatibility for Transactions**: Enabled clients to unmarshal old transactions, maintaining compatibility with previous network versions. #### Documentation and Maintenance Updates - **Default Module Parameter Values**: Set research-approved default values for module parameters, aligning implementation with theoretical models. - **Preservation of `codec.go` Files**: Ensured `codec.go` files are retained during proto generation, improving developer experience and code stability. ### Bug Fixes - **Score Normalization**: Adjusted score normalization to account for a broader range of samples, enhancing scoring accuracy and reliability. - **Whitepaper Alignment**: Corrected reward fraction calculations to match Whitepaper specifications, addressing discrepancies in implementation. ### Security Enhancements - **IBC MsgTransfer Validation**: Strengthened security by ensuring funds transferred via IBC MsgTransfer are reliably received, mitigating potential vulnerabilities. --- ## v0.7.0 **Release Date: December 2024** ### Key Features and Improvements #### Enhanced Reward Distribution Management - Optimized Topic Initialization: Initial regret values for topics have been adjusted (#670), improving accuracy in reward cycles and minimizing extreme variations for new topics. - Reputer Listening Coefficients: A new strategy for handling reputer listening coefficients (#683) ensures better responsiveness in reward cycles, addressing inefficiencies in past implementations. - Expanded Governance and Module Permissions Burner Permission Added to Governance Module: The governance module now supports burner permissions, enhancing flexibility in token management within proposals (#685). Fee Market and Fee Grant Module Integration: Introduced a fee market and fee grant module (#627), enabling advanced transaction fee mechanisms and improving usability. #### Advanced Sortition and Migration Updates - Whitelist Features: Added whitelist support for admins, topic creators, workers, and reputers, alongside the x/emissions v6 migration and chain upgrade (#663). This ensures better control over permissions and enhances network security. - Optimistic Execution and CometBFT Upgrade: Implemented optimistic execution with CometBFT v0.38.15 (#678), offering faster and more efficient block processing. - Circuit Breaker for AnteHandler: The new CircuitBreakerDecorator (#689) introduces an additional layer of safety during transaction execution. #### Improved Tooling and Developer Experience - Fuzzer Enhancements: Linter integration and fuzzer improvements ensure state transitions add up to 100% (#654). Setup now runs through all state transitions once before starting fuzzing (#650), with additional bug fixes and probability configuration options (#653). - CLI Query Alignment: Refined CLI query commands to standardize user experience (#686). - Migration Tests and Upgrade Guides: Updated migration tests (#693) and added an upgrade guide to contributing documentation (#697). ### Bug Fixes - Stake Validation: Implemented nil amount validation for stakes and added robust test coverage (#668). - Reputer Nonce Boundaries: Resolved boundary issues in nonce submissions, ensuring accurate validation (#687). - Investor Token Unlocks: Adjusted investor token unlock mechanisms to ensure strictly monotonically increasing amounts (#690). ### Documentation and Maintenance - Documentation Enhancements: Added detailed documentation to CONTRIBUTING.md (#698), improving developer onboarding and alignment with governance and emissions modules. - Mint Module Updates: Fixed inconsistencies in the mint module's GenesisState and proto definitions, with a no-op v3 migration (#695). ### Security Enhancements - IBC MsgTransfer Validation: Ensured that funds sent via IBC MsgTransfer are securely received (#682), addressing a critical security concern. ## v0.6.0 **Release Date: October 2024** ### Key Features and Improvements #### Reward Distribution Management - A new field keeps track of the sum of active topics' weights over time, ensuring more accurate reward distribution. - Rewards are now accumulated across blocks rather than being recalculated every block. - The network now handles inactive or reactivated topics more efficiently, ensuring the total weights are always accurate for reward calculations. #### Runaway Negative Regret Calculations - The network now tracks initial regrets more carefully, particularly for fast-iteration topics, where regrets previously became excessively negative. - By only including experienced participants in regret calculations, it prevents a "runaway effect" where negative regrets grow too large. - New participants will have their regrets based on more stable values from established users, helping to balance the regret system and encourage continuous participation without penalizing newcomers too harshly. #### Improved Merit-Based Sortitioning - The network now has enhanced merit-based sortitioning by calculating participants' percentile rankings using instantaneous scores instead of Exponential Moving Averages (EMAs). - This change allows for quicker cycling through participants, ensuring that high-performing actors can be selected faster for rewards and network involvement. - The faster update to scores improves responsiveness, allowing new talent to enter the active set more easily and giving the network more up-to-date performance data, all while maintaining a merit-based selection process. ## v0.5.0 **Release Date**: September 2024 The Allora Network v0.5.0 is now live! This version introduces several major updates designed to enhance user experience, improve network performance, and bolster system stability. Below are the key features, improvements, and bug fixes included in this release. ### Key Features and Improvements #### Fixes from v0.4.0 Upgrade Migration - Resolved issues related to the incomplete migration of topic fields from the v0.4.0 upgrade. This fix ensures smoother transitions between versions and enhances data integrity during future upgrades. #### New RPC Endpoint for Emission Rate Control - A new RPC endpoint has been introduced to give administrators the ability to recalculate inflation rates and manage target emission rates more frequently than the standard monthly recalculation. This provides greater flexibility and control over token emissions. #### Refined Topic Management - **Rewardable Topics as Active Topics**: v0.5.0 merges the categories of rewardable and active topics, with rewardable topics now serving as the primary active ones. This simplifies topic management and includes renaming of core functions to improve clarity and system efficiency. #### Event Monitoring for Research and Insights - New event triggers have been added to enable a research monitoring suite. These event triggers will assist researchers and developers in tracking network behaviors and studying system performance with deeper insights. ### Bug Fixes #### Handling NaN (Not a Number) Issues - Fixed issues related to NaN values appearing in various calculations: - NaN values in maps during migrations have been cleared. - Protection against NaN in the Exponential Moving Average (EMA) calculations has been added, ensuring accurate scoring and reward computations. #### Improved Migration Testing - Enhanced migration tests have been introduced to catch issues surrounding Initial Regrets, improving the reliability of future upgrades by addressing potential edge cases. #### Reputation System Improvements - Adjustments have been made to how block heights and score calculations are handled within the reputation system. This prevents redundant score submissions and ensures a fair reward distribution across the network. ### Security Enhancements #### Max Length Limits on Topic Creation - Maximum string length limits have been enforced for new topics to prevent overflow issues and mitigate the risk of malicious input, contributing to a more secure system environment. #### Idempotent Payload Submission - Simplified submission conditions for inference payloads. Duplicate submissions are now handled in an idempotent manner, preventing them from affecting the system's behavior or causing erroneous calculations. ## v0.4.0 **Release Date**: September 2024 This version focuses on implementing key fixes from the June 2024 Sherlock.xyz audit, enhancing active topic management, and refining the scoring system. Below are the critical updates, new features, and fixes included in this release. ### Key Features and Improvements #### Scalable Management of Active Topics - **Active Topic Queries**: Introduced scalable solutions for managing active topics with new queries such as `GetActiveTopicsAtBlock` and `GetNextChurningBlockByTopicId`. These additions enhance the network's ability to efficiently retrieve topic statuses at specific blocks and predict future churn events for each topic. #### Exponential Moving Average for Scores - **Smoother Scoring**: Transitioned to using an **Exponential Moving Average (EMA)** for score calculations, replacing the previous instantaneous score values from each epoch. This change smooths out score fluctuations and ensures a more representative scoring system over time. ### Removed #### Deprecated Unpartitioned Active Topic Queries - As part of the new scalable topic management system, the outdated `GetActiveTopics` query and paginated versions were removed. This helps streamline how active topics are stored and queried in the system. ### Bug Fixes #### Reward Conversion to cosmosInt - Implemented a check to prevent **zero-rewards** after conversion to `cosmosInt`, ensuring rewards are correctly handled and distributed. #### InsertPayload Error Handling - Improved error handling in the `InsertPayload` function, along with enhanced testing for error scenarios. This strengthens payload processing and prevents errors from affecting the overall system. #### Reputer Window Limit Fix - Fixed the **Reputer window upper limit** to ensure that reputation calculations do not exceed the intended thresholds. #### Worker Nonce Window Timing - Resolved an issue where the **worker nonce window** was prematurely closing as soon as it opened, preventing proper timing of nonce submissions. ### Security Enhancements #### Signature Verification for Payloads - Added checks to ensure that signatures on **Worker or Reputer Payloads** match the corresponding `Inferer`, `Forecaster`, or `Reputer` inside the bundle. This prevents unauthorized manipulation of payloads and strengthens overall network security. ## v0.3.0 **Release Date**: August 2024 The Allora Network v0.3.0 introduced a significant update focused on enhancing participant selection through a merit-based system. This update addresses the need to balance limited on-chain compute resources while ensuring fair opportunities for new participants. Below are the key features, changes, and improvements implemented in this release. ### Key Changes Implemented #### The Need for Merit-Based Sortition - To manage the constraints of on-chain compute while avoiding a "rich get richer" scenario, Allora Network introduced **merit-based sortition**. This process selects high-quality participants each epoch based on their past performance, measured by a running average of their scores. At the same time, lower-performing participants are cycled out, allowing new talent to demonstrate its value. #### Active and Passive Sets Management - **Active Set**: A group of high-performing participants whose data is used to calculate network inferences and receive rewards. The chain determines who qualifies for the active set by calculating a running average of each participant's scores. - **Passive Set**: Participants who are not in the active set move into the passive set. While their data isn't used for final rewards, their inferences are still tracked and considered for future inclusion in the active set, giving them a chance to re-enter based on improved performance. #### Score Calculation Using Exponential Moving Averages (EMAs) - **EMA-Based Score Calculation**: Scores for each participant are calculated using an Exponential Moving Average (EMA). This method smooths out individual performance over time, preventing large score fluctuations from one epoch to the next, and ensuring a more stable evaluation process. ### Merit-Based Participant Selection The merit-based sortition system helps maintain the quality of network inferences while giving fresh talent the opportunity to participate and prove their value. This mechanism is designed to strike a balance between performance-based selection and inclusivity for new participants.