# 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.]

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 input arguments (`wasm_args`) 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, policy_data) 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 [Secrets in Oracles](/developers/guides/secrets-in-oracles)) | — (read inside the WASM) |
| `params_schema.json` | Policy thresholds the contract owner configures | `data.params.*` |

Callers pass `wasm_args` as hex-encoded JSON on `newt_createTask` / `newt_simulatePolicyData`. 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 with empty args
newton-cli policy-data simulate --wasm-file policy.wasm --input-json '{}'

# Simulate with specific args
newton-cli policy-data simulate \
  --wasm-file policy.wasm \
  --input-json '{"base_symbol": "BTC"}'
```

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_data_address": "0x...",
      "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">
  Deploy your oracle and policy to IPFS and on-chain
</Card>
