Flux docs
Search…
Data Requesters
How to set up your smart contract as a Data Requester with the testnet deployment of Flux on NEAR
Follow along with our Youtube tutorial! You should be able to set up your account and Data Requester contract within 15 minutes!

Prerequisites

    You want to create an access point to the Flux Oracle for creating data requests to be resolved by Flux validators
    You are comfortable with the command line, GitHub, crypto wallets, and editing/deploying smart contracts
    You acknowledge this is a testnet version and inclusion into the Requester Registry on mainnet requires a successful proposal and execution with the Flux DAO, and each data request will require the posting of a validity bond (no real funds are required for testnet). More information on how to submit a proposal to the Flux DAO will be included at a later date.

Setting up the contract

If you haven't deployed a contract yet on NEAR, follow the instructions here to set up a testnet account, the Rust environment, and the NEAR CLI.
Once you've sorted that out, you can clone the requester-sample-contract here.
First, login to your NEAR testnet account using the near login cli command and fill in the information in order to add your account credentials locally and run the rest of the commands.
Open your terminal and cd into the folder, and run the following command, replacing YOUR_TESTNET_ACCT_ID with your actual testnet account id.
1
sh build.sh
2
sh scripts/deploy_requester.sh --accountId YOUR_TESTNET_ACCT_ID.testnet
Copied!
In the mainnet release, you will first need to request to have your contract whitelisted with the Flux DAO before you will be able to interact with the oracle. But you're in luck! We're going to give you the chance to test it out, bureaucracy-free!

Making a Request

Now that you have your contract deployed on your testnet account, it's time to fire up a request! Data requests are created by calling a method on the Requester contract (typically named create_data_request()) to forward a payment bond to the oracle by calling the token contract with the new request payload.
1
pub fn create_data_request(
2
&self,
3
amount: WrappedBalance,
4
payload: NewDataRequestArgs
5
) -> Promise {
6
fungible_token_transfer_call(
7
self.stake_token.clone(),
8
self.oracle.clone(),
9
amount.into(),
10
json!({"NewDataRequest": payload}).to_string()
11
)
12
}
Copied!
As you can see, each data request has an amount and a payload in it. The amount is the validity_bond that you must post with the request in order to interact with the oracle. This is in place to deter malicious actors from spamming the oracle with invalid requests, unless they actually wish to lose all of their money to validators. If your request is deemed invalid by the validators, your bond will be kept by the treasury.
Every request must come with a payload that contains some or all of the following arguments:
1
pub struct NewDataRequestArgs {
2
pub sources: Vec<Source>, // for api DR types, can be left as "[]" if arbitrator DR type
3
pub tags: Option<Vec<String>>, // for searching DR types
4
pub description: Option<String>, // question if arbitrator type, details
5
pub outcomes: Option<Vec<String>>, // for predefining outcomes of DR
6
pub challenge_period: WrappedTimestamp, // milliseconds, duration validators can challenge top outcome
7
pub data_type: DataRequestDataType, // type of data DR outcome is
8
pub creator: AccountId, // creator of DR
9
}
Copied!
The Source is:
1
pub struct Source {
2
pub end_point: String, // api endpoint, where validator can retrieve outcome
3
pub source_path: String // json path to outcome
4
}
Copied!
For API Data Requests, or requests with outcomes that can be retrieved from certain API endpoints, fill in the end point with the API endpoint[s], and the source_path with the path (ex. JSON path) to get to the desired value[s]. For example:
1
\"sources\": [
2
{
3
\"end_point\": \"https://api.coingecko.com/api/v3/coins/bitcoin/market_chart/range?vs_currency=usd&from=1629805695&to=1629806000\",
4
\"source_path\": \"prices[\$\$last][1]\"
5
}
6
]
Copied!
For arbitrator requests, or requests that usually require a human to answer, You can leave the sources without any values. For example:
1
\"sources\": []
Copied!
NOTE: your requests should have an explicit delimited outcome that cannot vary by time or place. For example, requesting the current price of bitcoin can vary based on the time a validator provides it, or which exchange / source they used. Provide an explicit end point to get the data from and an epoch or duration within which the data should be acquired in order for your request to be marked as valid and not have your bond taken.
The DataRequestDataType is:
1
pub enum DataRequestDataType {
2
Number(U128), // if outcome is a number
3
String, // if outcome is text
4
}
Copied!
If you're expecting your outcomes to be a number, fill in the data_type field as Number with the value being the multiplier for the number. For example:
1
\"data_type\":{\"Number\":\"10000000000\"}
Copied!
If you're expecting the outcome to be a string, you can fill in the data_type field with the String value like this:
1
\"data_type\":\"String\"
Copied!
Use tags to categorize a data request for easier querying later on when the outcome is needed. Tags are very flexible and can be used to group together multiple data request types. In our example, we use an auto-incrementing number to easily associate each data request with it's outcome.
The description can be filled at the of the data being requested, e.g.: “What was the closing price of Bitcoin on the 1st of December 2020?”
As an option, you can add a list of expected possible outcomes as the value for the outcomes field. It can also be left empty in case of an arbitrary answer, like from a price feed.
The challenge_period is the window of time for validators to stake on outcomes once the settlement time is reached. This period has a minimum term of 300.000ms (5 minutes) and a maximum term of 86.400.000ms (24 hours).
The creator of the data request, often set automatically by the Request Interface.

API Requests

Many requests will be made that will require an answer from a particular API location. In this case, you must fill out the end_point and source_path in the sources section such that a singular outcome can be found. If you are a protocol that needs to make automated requests, you can do so quite easily by setting up API requests.
Once filled in, the data request arguments can look like this:
1
"{
2
\"amount\": \"1000000000000000000000000\",
3
\"payload\": {
4
\"sources\": [
5
{
6
\"end_point\": \"https://api.coingecko.com/api/v3/coins/bitcoin/market_chart/range?vs_currency=usd&from=1629805695&to=1629806000\",
7
\"source_path\": \"prices[\$\$last][1]\"
8
}
9
],
10
\"tags\":[\"pricing\",\"btc\"],
11
\"challenge_period\":\"120000000000\",
12
\"settlement_time\":\"1\",
13
\"data_type\":{
14
\"Number\":\"10000000000\"
15
},
16
\"creator\":\"YOUR_TESTNET_ACCOUNT_ID\"
17
}
18
}"
Copied!
When you're ready, you can execute your data request using the following commands, or run sh scripts/request.sh YOUR_TESTNET_ACCOUNT_ID :
1
env NEAR_ENV=testnet
2
3
TIME=`date +%s`
4
END_TIME=`expr $TIME`
5
BEGIN_TIME=`expr $END_TIME - 300`
6
SOURCES="[{ \"source_path\": \"0.close\", \"end_point\": \"https://api.coinpaprika.com/v1/coins/btc-bitcoin/ohlcv/historical?start=$BEGIN_TIME&end=$TIME\" }, { \"end_point\": \"https://api.coingecko.com/api/v3/coins/bitcoin/market_chart/range?vs_currency=usd&from=$BEGIN_TIME&to=$TIME\", \"source_path\": \"prices[\$\$last][1]\" }]"
7
JSON="{\"sources\": $SOURCES,\"tags\":[\"1\"],\"description\":\"What is the price of BTC?\",\"challenge_period\":\"120000000000\",\"settlement_time\":\"1\",\"data_type\":{\"Number\":\"10000000000\"},\"creator\":\"your_account_id.flux-dev\"}"
8
env NEAR_ENV=testnet near call $1 create_data_request "{\"amount\": \"1000000000000000000000000\", \"payload\": $JSON}" --accountId $1 --amount 0.000000000000000000000001 --gas=300000000000000
Copied!
Voilà, you have made your first data request!

Arbitrator (human) requests

What if your request does not have a particular API from which you would like the answer? No problem!
Simply include the question in the description, change the data_type and leave the sources empty.
1
JSON="{\"sources\": [],\"tags\":[\"sports\",\"nfl\"],\"description\":\"Which team won the NFL Super Bowl in 1996?\",\"challenge_period\":\"120000000000\",\"settlement_time\":\"1\",\"data_type\":\"String\",\"creator\":\"your_account_id.flux-dev\"}"
2
env NEAR_ENV=testnet near call $1 create_data_request "{\"amount\": \"1000000000000000000000000\", \"payload\": $JSON}" --accountId $1 --amount 0.000000000000000000000001 --gas=300000000000000
Copied!

Getting outcome of requests

Once you have successfully sent your request, you can check on the progress in the Oracle Explorer, see who is staking, and what the potential outcomes are. After an outcome, or answer to your request, has been provided that has sufficient bond, and there are no disputes against it, you will receive your outcome via the set_outcome function that is called by the oracle. In our sample contract, the outcome is stored in the data_responses lookup map with the same key (auto-incremented value) as it's corresponding data request.
To check out your request and response (the request outcome), run sh scripts/response.sh YOUR_TESTNET_ACCOUNT_ID NONCE to get the request information and corresponding outcome:
1
sh scripts/response.sh YOUR_TESTNET_ACCOUNT_ID YOUR_REQUEST_NONCE
Copied!
The get_data_request function will return Option<DataRequest> and the get_data_response function will return Option<DataResponse> .
To find out more about how Data Requests flow through the Oracle, check out the Data Requests section here.
Last modified 17d ago