# Writing Data Oracles \[Build WebAssembly data oracles that fetch external data for Newton Protocol policy evaluation. JavaScript, Rust, and Python examples with the WIT component model.]

:::note
Attach an oracle's WASM module and optional secrets schema directly to its Policy. A policy set passes `wasm_args` as an ordered array, with one input for each Policy; individual WASM simulation uses one scalar input. See [Deploying with CLI](/developers/guides/deploying-with-cli) and the [RPC API](/developers/reference/rpc-api) for deployment and simulation.
:::

Data oracles are WebAssembly (WASM) components that fetch or compute external data at evaluation time. The Newton network executes your WASM, and the output is fed into your Rego policy as `data.wasm`.

## What is a Data Oracle?

A data oracle is a JavaScript (or Rust/Python) program compiled to WASM that:

1. Receives its Policy's `wasm_args` entry as a JSON string
2. Optionally fetches external data via HTTP
3. Returns a JSON string that becomes available to your Rego policy as `data.wasm`

## WIT Interface

Every data oracle implements the `newton-provider` WIT (WebAssembly Interface Types) contract. Create `newton-provider.wit`:

```
package newton:provider@0.2.0;

// HTTP host interface
interface http {
    record http-request {
        url: string,
        method: string,
        headers: list<tuple<string, string>>,
        body: option<list<u8>>,
    }

    record http-response {
        status: u16,
        headers: list<tuple<string, string>>,
        body: list<u8>,
    }

    fetch: func(request: http-request) -> result<http-response, string>;
}

// Secrets host interface
interface secrets {
    record secret-response {
        // Raw bytes of the decrypted secrets JSON object.
        // The scope (policy client and Policy) is bound by the host execution context.
        value: list<u8>,
    }

    get: func() -> result<secret-response, string>;
}

// [NEW] TLSNotary verification interface
interface tlsn {
    record verified-data {
        /// Authenticated server name (e.g. "api.x.com")
        server-name: string,
        /// Unix timestamp (seconds) of the TLS connection
        connection-time: u64,
        /// Sent transcript bytes (unauthenticated bytes masked as 0x58 'X')
        sent-transcript: list<u8>,
        /// Received transcript bytes (unauthenticated bytes masked as 0x58 'X')
        received-transcript: list<u8>,
        /// SHA-256 fingerprint of the presentation notary verifying key, hex-encoded.
        notary-key-fingerprint: string,
    }

    /// Download a TLSNotary Presentation from IPFS by CID, verify it, and return authenticated data.
    ///
    /// The host implementation:
    ///   1. Downloads from IPFS (5 MiB cap — returns error if exceeded)
    ///   2. Re-verifies the CID multihash against the downloaded bytes (defends against malicious IPFS gateways)
    ///   3. BCS-deserializes the bytes into a Presentation
    ///   4. Calls verify_presentation() from newton-tls-notary
    ///
    /// This bypasses the WASM HTTP 1 MiB limit since the host fetches directly.
    verify-from-cid: func(proof-cid: string) -> result<verified-data, string>;

    /// Verify a TLSNotary Presentation from raw BCS-serialized bytes.
    ///
    /// Useful for small proofs or testing where bytes are already available.
    verify: func(presentation-bytes: list<u8>) -> result<verified-data, string>;
}

world newton-provider {
    import http;
    import secrets;
    import tlsn;

    export run: func(input: string) -> result<string, string>;
}
```

The `http` import provides the `fetch` function for making HTTP requests from within the WASM sandbox. The `run` export is your oracle's entry point.

## Implement in JavaScript

Create `policy.js`:

```js
import { fetch as httpFetch } from "newton:provider/http@0.2.0";

export function run(wasm_args) {
  const args = JSON.parse(wasm_args);

  // Example: fetch an external API
  const result = httpFetch({
    url: `https://api.example.com/data?symbol=${args.base_symbol}`,
    method: "GET",
    headers: [["Accept", "application/json"]],
    body: null,
  });

  if (result.tag === "err") {
    return JSON.stringify({ error: result.val });
  }

  const response = result.val;

  if (response.status !== 200) {
    return JSON.stringify({ error: "API request failed" });
  }

  const body = JSON.parse(
    new TextDecoder().decode(new Uint8Array(response.body))
  );

  return JSON.stringify({
    price: body.price,
    symbol: args.base_symbol,
    timestamp: Date.now(),
  });
}
```

:::note
Import `httpFetch` from `newton:provider/http@0.2.0` at the top level of your module. The function returns a tagged result: when `result.tag === "err"`, `result.val` contains the error string; otherwise `result.val` is the HTTP response with `status`, `headers`, and `body`.
:::

:::warning
**WASM sandbox network restrictions**: Newton operators execute WASM in sandboxed Wasmtime. Private IPs (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`), loopback (`127.0.0.1`), and link-local (`169.254.0.0/16`) are blocked. Any HTTP endpoint your WASM calls must be on a public URL.
:::

## Declare the input schema

The `wasm_args` your oracle receives are documented and validated by a `wasm_args_schema.json` file — a JSON Schema describing the inputs passed to `run(input)` at evaluation time. Ship it alongside your oracle so callers know exactly what to send.

```json
{
  "type": "object",
  "description": "Inputs passed to the oracle WASM at evaluation time",
  "properties": {
    "network": {
      "type": "string",
      "description": "Network name (e.g. 'mainnet', 'base')."
    },
    "vaultAddress": {
      "type": "string",
      "description": "Vault contract address (0x-prefixed) to inspect."
    }
  },
  "required": ["network", "vaultAddress"]
}
```

An oracle ships up to three schemas, each describing a distinct input:

| Schema file | Describes | Read in Rego as |
|-------------|-----------|-----------------|
| `wasm_args_schema.json` | Per-call inputs passed to the oracle's `run(input)` (the `wasm_args` on each task) | — (consumed by the WASM, not Rego) |
| `secrets_schema.json` | Scoped credentials the oracle reads via the secrets host interface (see [Deploying with CLI](/developers/guides/deploying-with-cli)) | — (read inside the WASM) |
| `params_schema.json` | Policy thresholds the contract owner configures | `data.params.*` |

For task creation and full-policy simulation, callers pass this oracle's hex-encoded JSON input in its position in the `wasm_args` array. Individual WASM simulation accepts the same value as a scalar. Validating against this schema before submission catches malformed inputs early.

## Build WASM

Compile the JavaScript into a WASM component using `jco`:

```bash
# Install jco globally (if not already)
npm install -g @bytecodealliance/jco @bytecodealliance/componentize-js

# Build the WASM component
jco componentize -w newton-provider.wit -o policy.wasm policy.js \
  -d stdio random clocks http fetch-event
```

This produces `policy.wasm` in the current directory.

:::note
If you installed `jco` locally (without `-g`), run it via `npx jco componentize ...` instead.
:::

## Test Locally

Test your WASM oracle before deploying:

```bash
# Simulate the policy that contains this WASM module
newton-cli policy simulate -p policies/my-oracle

# Change configs/wasm_args.json to exercise specific oracle input,
# then run the same command again.
```

You can also test via the Gateway RPC:

```bash
curl -X POST https://gateway.testnet.newton.xyz/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your_api_key>" \
  -d '{
    "jsonrpc": "2.0",
    "method": "newt_simulatePolicyData",
    "params": {
      "policy_address": "0x...",
      "chain_id": 11155111,
      "wasm_args": "0x7b22626173655f73796d626f6c223a22425443227d"
    },
    "id": "7ca6621b-7aa4-4bb7-a896-1f2b58a18c78"
  }'
```

## Alternative Languages

While JavaScript is the most common choice, you can also write data oracles in:

* **Rust** — see the [Rust WASM Guide](/developers/advanced/rust-wasm-guide)
* **Python** — see the [Python WASM Guide](/developers/advanced/python-wasm-guide)

All languages compile to the same WIT interface and produce interchangeable WASM components.

## Next Steps

<Card icon="file-code" to="/developers/guides/writing-policies" title="Writing Policies">
  Write a Rego policy that uses your oracle's output
</Card>

<Card icon="rocket" to="/developers/guides/deploying-with-cli" title="Deploying with CLI">
  Build, simulate, and deploy a Policy with an optional WASM module
</Card>
