witnet / witnet-requests-js

Witnet Requests Javascript Library
MIT License
5 stars 11 forks source link

Add support for HTTP-POST, GraphQL sources, XML parsing and headers in HTTP-GET for rad2sol and toolkit #66

Closed aesedepece closed 2 years ago

aesedepece commented 2 years ago

Supersedes #58 Related to https://github.com/witnet/witnet-rust/issues/2186

aesedepece commented 2 years ago

This request:

// Retrieve VSQ/DAI-6 price from the SushiSwap DEX API:
const sushiswap = new Witnet.GraphQLSource(
  "https://api.thegraph.com/subgraphs/name/sushiswap/matic-exchange",
  `{ pair(id: "0x102d39bc293472dc9ac3e6a0a9261a838b3bc6d7") { token0Price }}`,
  {"Content-Type": "application/json"}
  )
  .parseJSONMap()
  .getMap("data")
  .getMap("pair")
  .getFloat("token0Price") // Get the `Float` value associated to the `price` key
  .multiply(10 ** 6) // Use 6 digit precision
  .round() // Cast to integer

// Filters out any value that is more than 1.5 times the standard
// deviationaway from the average, then computes the average mean of the
// values that pass the filter.
const aggregator = new Witnet.Aggregator({
  filters: [
    [Witnet.Types.FILTERS.deviationStandard, 1.5],
  ],
  reducer: Witnet.Types.REDUCERS.averageMean,
})

// Filters out any value that is more than 1.5 times the standard
// deviationaway from the average, then computes the average mean of the
// values that pass the filter.
const tally = new Witnet.Tally({
  filters: [
    [Witnet.Types.FILTERS.deviationStandard, 2.5],
  ],
  reducer: Witnet.Types.REDUCERS.averageMean,
})

// This is the Witnet.Request object that needs to be exported
const request = new Witnet.Request()
  .addSource(sushiswap)
  .setAggregator(aggregator) // Set the aggregator function
  .setTally(tally) // Set the tally function
  .setQuorum(10, 51) // Set witness count and minimum consensus percentage
  .setFees(10 ** 6, 10 ** 6) // Set economic incentives
  .setCollateral(5 * 10 ** 9) // Require 5 wits as collateral

now compiles to:

0a8e0212ed010803124068747470733a2f2f6170692e74686567726170682e636f6d2f7375626772617068732f6e616d652f7375736869737761702f6d617469632d65786368616e67651a2c861877821866646461746182186664706169728218646b746f6b656e3050726963658218571a000f4240185b22577b227175657279223a227b20706169722869643a205c223078313032643339626332393334373264633961633365366130613932363161383338623362633664375c2229207b20746f6b656e305072696365207d7d227d2a200a0c436f6e74656e742d5479706512106170706c69636174696f6e2f6a736f6e1a0d0a0908051205fa3fc000001003220d0a0908051205fa40200000100310c0843d180a20c0843d28333080e497d012

which in turn gets executed as:

╔════════════════════════════════════════════╗
║ Witnet data request local execution report ║
╚╤═══════════════════════════════════════════╝
 │
 │  ┌────────────────────────────────────────────────┐
 ├──┤ Retrieval stage                                │
 │  ├────────────────────────────────────────────────┤
 │  │ Number of retrieved data sources: 1            │
 │  └┬───────────────────────────────────────────────┘
 │   │
 │   └─[ Source #0 (api.thegraph.com) ]
 |      Method: HTTP-POST
 |      Complete URL: https://api.thegraph.com/subgraphs/name/sushiswap/matic-exchange
 |      Headers: 
 |        "Content-Type": "application/json"
 |      Body: {"query":"{ pair(id: \"0x102d39bc293472dc9ac3e6a0a9261a838b3bc6d7\") { token0Price }}"}
 |      Number of executed operators: 6
 |      Execution time: 0.04084 ms
 |      Execution trace:
 │        [0] HTTP-POST -> String: "{\"data\":{\"pair\":{\"token0Price\":\"5.129891757693646219179744979435213\"}}}"
 │        [1] .parseJSONMap() -> Map: {"data":{"RadonMap":{"pair":{"RadonMap":{"token0Price":{"RadonString":"5.129891757693646219179744979435213"}}}}}}
 │        [2] .getMap(data) -> Map: {"pair":{"RadonMap":{"token0Price":{"RadonString":"5.129891757693646219179744979435213"}}}}
 │        [3] .getMap(pair) -> Map: {"token0Price":{"RadonString":"5.129891757693646219179744979435213"}}
 │        [4] .getFloat(token0Price) -> Float: 5.129891757693646
 │        [5] .multiply(1000000) -> Float: 5129891.7576936465
 │        [6] .round() -> Integer: 5129892
 |      Result: Integer: 5129892
 │
 │  ┌────────────────────────────────────────────────┐
 ├──┤ Aggregation stage                              │
 │  ├────────────────────────────────────────────────┤
 │  │ Execution time: 0.0045 ms                      │
 │  │ Result is Integer: 5129892                     │
 │  └────────────────────────────────────────────────┘
 │  
 │  ┌────────────────────────────────────────────────┐
 └──┤ Tally stage                                    │
    ├────────────────────────────────────────────────┤
    │ Execution time: 0.00107 ms                     │
    │ Result is Integer: 5129892                     │
    └────────────────────────────────────────────────┘
aesedepece commented 2 years ago

(In the example above, the headers field was strictly not needed, but added it as an example and proof that it works!)