---
# System prepended metadata

title: Becoming a BandChain Data Provider

---

# Becoming a BandChain Data Provider

This documentation provides technical instruction on how to onboard as a data provider for BandChain oracle network.

## Summary

As a data provider, you are responsible for uploading your *data source scripts* to BandChain that describes how a validator can fetch data points from your server. Your serve must expose a public HTTP endpoint accessible by the validators. Validators sign their requests with their private keys and your server can cross-check the validity of the signatures with a BandChain node. You can run a node internally or utilize a public node run by the foundation. 

## Specification

A [data source](https://docs.staging.bandprotocol.com/whitepaper/terminology.html#data-sources) has access to the following environment variables:


| Variable           | Description                                               |
| ------------------ | --------------------------------------------------------- |
| `BAND_CHAIN_ID`    | BandChain Chain ID                                        |
| `BAND_VALIDATOR`   | The validator processing this request                     |
| `BAND_REQUEST_ID`  | The request ID                                            |
| `BAND_EXTERNAL_ID` | The ID of the raw request that executes this data source. |
| `BAND_REPORTER`    | The reporter that works on behalf of the validator        |
| `BAND_SIGNATURE`   | The signature signed by the reporter                      |

The data source must pass all information to the data providers's server. The server can cross-check the validity of the environment variables using BandChain's `/oracle/verify_request` endpoint. 

See example server code below for the usage.

## Price Data Provider Endpoint

While in theory a data provider can design its server endpoint anyway they want, Band Protocol provides a standardized interface for data providers to allow fast onboarding and full-compatibility with existing data source implementation.

### Request Specification

The server must support one `POST` HTTP endpoint with the following headers and body.

**Headers** contains information passed along from data source environment variables. The server must check the header data with a BandChain node to verify that the requester is an authorized validator.

```
BAND_CHAIN_ID
BAND_VALIDATOR
BAND_REQUEST_ID
BAND_EXTERNAL_ID
BAND_REPORTER
BAND_SIGNATURE
```

**Body** is JSON-encoded data for price symbols to query. It is a JSON dictionary consisting of one key `symbols` that maps to a list of ticker symbols.

```json
{
    "symbols": ["BTC", "ETH"]
}
```

### Response Specification

The response must a JSON dictionary mapping from symbols to their prices denominated in USD.

```json
{
    "BTC": 10999.0,
    "ETH": 386.0,
}
```

### Example Request-Response

```bash
curl --location --request POST '<endpoint>' \
  --header 'BAND_VALIDATOR: bandvaloper1p40yh3zkmhcv0ecqp3mcazy83sa57rgjde6wec' \
  --header 'BAND_CHAIN_ID: bandchain' \
  --header 'BAND_REQUEST_ID: 4' \
  --header 'BAND_EXTERNAL_ID: 1' \
  --header 'BAND_REPORTER: bandpub1addwnpepq0awyhs0wc20dm99hugm8z2ee8ctlpsx6v4cs3v0dxw7fpl44tlc27hn0a6' \
  --header 'BAND_SIGNATURE: c6na2CxT/UmFW4UqgYqQagEN0oNeUiyGYJlkOchZ21QJ25wq6sRulsJLkGQBZcnn7J4zGOUUpIKoiLV46s32nw==' \
  --header 'Content-Type: application/json' \
  --data-raw '{"symbols": ["BTC", "ETH"]}'

# Response
{
    "BTC": 10999.0,
    "ETH": 386.0,
}
```

## Server Setup + Live Testing Guide

You will need to setup a webserver that serves the aforementioned endpoint. Under the hood, the request handler should perform the following tasks.

1. Validate the request headers required and verify the information with a BandChain node. Return error if BandChain returns a non-2XX HTTP status. This can be due to (1) invalid signature, (2) invalid validator/reporter, (3) invalid request id or request already expired, (4) invalid external id, or (5) request already reported by this validator.
2. The response from BandChain, if successful, will contain the request's data source ID.
3. Return error if the data source ID is not the one whitelisted by your organization.
4. You may have a de-duplication layer to ensure that you do not process the same `(Validator, RequestID, ExternalID)` tuple more than once.
5. If all verifications pass, your server should return price data points back to the requesting validator. 

Following is an example mockup server code written in [Flask](https://flask.palletsprojects.com/) (deployed at https://verify-data-provider.herokuapp.com).

```python
import requests
from flask import Flask, jsonify, request


BANDCHAIN_NODE_URL = "https://guanyu-testnet3.bandchain.org/rest/oracle/verify_request"
WHITELISTED_DATA_SOURCES = [2]
PRICES = {
    "BTC": 11050.89,
    "ETH": 383.99,
}

app = Flask(__name__)
# Do not use in production. Memory leak!
dedup = {}


def get_header(flag):
    return request.headers.get(flag)


@app.route("/", methods=["POST"])
def get_data():
    # Not allow dulplicate request on the same validator, request id and external id
    identity = (get_header("BAND_VALIDATOR"), get_header("BAND_REQUEST_ID"), get_header("BAND_EXTERNAL_ID"))
    if identity in dedup.keys():
        return jsonify({"error": "already processed"}), 400
    dedup[identity] = True

    resp = requests.post(
        BANDCHAIN_NODE_URL,
        json={
            "chain_id": get_header("BAND_CHAIN_ID"),
            "validator": get_header("BAND_VALIDATOR"),
            "request_id": get_header("BAND_REQUEST_ID"),
            "external_id": get_header("BAND_EXTERNAL_ID"),
            "reporter": get_header("BAND_REPORTER"),
            "signature": get_header("BAND_SIGNATURE"),
        },
    )

    if resp.status_code != 200:
        return jsonify({"error": resp.json()["error"]}), resp.status_code

    result = resp.json()["result"]
    if int(result["data_source_id"]) not in WHITELISTED_DATA_SOURCES:
        return jsonify({"error": "wrong data source id"}), 400

    req = request.get_json()
    prices = {}
    try:
        for symbol in req["symbols"]:
            prices[symbol] = PRICES[symbol]
        return jsonify(prices), 200
    except:
        return jsonify({"error": "unknown symbol"}), 400


if __name__ == "__main__":
    app.run()
```

Once you have the server up and running, you can test it in live environment on BandChain GuanYu testnet network. Go to the testnet [explorer](https://guanyu-testnet3.cosmoscan.io) click on Connect.

![](https://i.imgur.com/ulgM2NQ.png)

Fill in any string name for test purpose to generate a new account.

![](https://i.imgur.com/AzX09iD.png)

Clicking `Get 10 Testnet BAND` to request testnet BAND tokens.

![](https://i.imgur.com/x2MTAPS.png)

After you receive the testnet BAND token, go to `Oracle  Scripts` tab select `#O2` this is our test oracle script to get data from any data source.

![](https://i.imgur.com/0BdmlTS.png)

Then click `Make New Request`

![](https://i.imgur.com/71jtUbz.png)

Paste your server endpoint in `Endpoint` field. `Symbols` is the list of symbol that want to request. Ask count is the number of validators that will be assigned to make a request to your endpoint. Then click `Request` button
![](https://i.imgur.com/0f6lm7L.png)

If transaction has been sent successfully, we can wait for validator to query data (send request to your server) after a few second request should be resolved, and you will see the output of this request. If you want to see more detail of this request, you can click at `#R..`

![](https://i.imgur.com/16Hl3Mc.png)

![](https://i.imgur.com/l9E4mfS.png)

![](https://i.imgur.com/LNxSBFB.png)
