# fialucci-oracle

[![crates.io](https://img.shields.io/crates/v/fialucci-oracle.svg)](https://crates.io/crates/fialucci-oracle)
[![docs.rs](https://img.shields.io/docsrs/fialucci-oracle)](https://docs.rs/fialucci-oracle)

Opinionated SDK for building external oracles on the [Fialucci](https://github.com/fialucci) chain.

```toml
[dependencies]
fialucci-oracle = "0.0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
async-trait = "0.1"
```

## What this is

A Rust crate developers import to **build an oracle** — a process that observes some off-chain source and asserts claims about it on the Fialucci chain. The SDK ships an opinionated runtime; developers customize **only** the business logic by implementing one trait, [`OracleHandler`].

## What the dev controls — and what they don't

Three things must be byte-identical between every oracle in the wild and the chain validating its submissions:

1. The proof body canonical JSON encoding.
2. The signing-bytes derivation (domain separator + body JSON).
3. The ed25519 signature.

Letting individual oracle authors re-implement any of these makes wire drift a question of when, not if. So the SDK owns all three:

| Concern | Owner |
|---|---|
| ed25519 keypair, signing | SDK (`OracleIdentity` — `sign_bytes` is crate-private) |
| Proof body construction (chain_id, nonce, timestamp, request binding) | SDK (runtime fills these in) |
| HTTP submission to the chain | SDK (`ChainClient`, fixed endpoint set) |
| Polling for matching observation requests | SDK (event loop) |
| **What claim to make and what evidence to attach** | **Dev** (`OracleHandler::observe`) |

The dev's surface is one async method.

## Quick start

```rust
use std::time::Duration;
use async_trait::async_trait;
use fialucci_oracle::{Oracle, OracleHandler, OracleIdentity, ObservationRequest, ProofClaimEvidence, HandlerError};
use fialucci_oracle::types::{ProofClaim, ProofEvidence, hash_evidence_bytes};

struct MyOracle;

#[async_trait]
impl OracleHandler for MyOracle {
    async fn observe(&self, request: &ObservationRequest) -> Result<Option<ProofClaimEvidence>, HandlerError> {
        // Whatever your oracle observes — a GitHub PR's merge state,
        // a price feed, a database row — produces some bytes.
        let evidence_bytes = b"observed bytes here";

        Ok(Some(ProofClaimEvidence {
            claim: ProofClaim::WorkCompleted,
            evidence: ProofEvidence {
                evidence_hash: hash_evidence_bytes(evidence_bytes),
                evidence_uri: None,
                content_type: Some("application/octet-stream".to_string()),
                metadata: None,
            },
        }))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let identity = OracleIdentity::load_from_file("oracle_key.json")?;
    let oracle = Oracle::builder()
        .identity(identity)
        .node_url("http://127.0.0.1:8080")
        .handler(MyOracle)
        .poll_interval(Duration::from_secs(5))
        .build()
        .await?;
    oracle.run().await?;
    Ok(())
}
```

See [`examples/manual_oracle.rs`](examples/manual_oracle.rs) for a runnable template.

## Getting an oracle identity

Generate one in-process:

```rust
use fialucci_oracle::OracleIdentity;
let identity = OracleIdentity::generate();
identity.save_to_file("oracle_key.json")?;
```

Or use the chain repo's `fialucci-oracle-keygen` binary — the keystore JSON format is identical, so a key generated by either tool works with the other.

The oracle still needs to be **registered** on the target chain (`oracles.json` registry, or the chain's auto-register feature) before its proofs are accepted.

## Endpoint surface

The SDK talks to a Fialucci chain node over these endpoints:

| SDK method | Chain endpoint |
|---|---|
| `ChainClient::chain_info` | `GET /chain-info` |
| `ChainClient::submit_submission` | `POST /oracle/submissions` |
| `ChainClient::matching_observation_requests` | `GET /oracle/observation-requests/matching?oracle_id=…` |
| `ChainClient::submit_observation_request_response` | `POST /oracle/observation-requests/{id}/submissions` |

If you need anything else, talk to the node with `reqwest` directly. The SDK's surface is intentionally narrow.

## Version compatibility

`fialucci-oracle` depends on `fialucci-types` from crates.io — the same crate the chain itself consumes. SDK SemVer tracks `fialucci-types` SemVer for wire-shape changes:

| `fialucci-oracle` | `fialucci-types` | Works against `fialucci-chain` versions |
|---|---|---|
| `0.0.1` | `0.0.2` | post-[PR #23](https://github.com/fialucci/fialucci-chain/pull/23) |

## License

Apache-2.0.
