Explorar o código

feat(hermes): release v2 initial API (#1293)

The V2 API provide more functionality compared to the V1 such as
supporting benchmark proofs for multiple ids. This change bumps the
Hermes version to initiate a release and also fixes a couple of minor
things:
- Update build.rs to not panic on rebuilds
- Remove an unused benchmarks file
- Add all the V2 endpoints to docs
Ali Behjati hai 1 ano
pai
achega
22579edc6e
Modificáronse 5 ficheiros con 8 adicións e 138 borrados
  1. 1 1
      hermes/Cargo.lock
  2. 1 1
      hermes/Cargo.toml
  3. 5 2
      hermes/build.rs
  4. 1 0
      hermes/src/api.rs
  5. 0 134
      hermes/src/api/benchmarks.rs

+ 1 - 1
hermes/Cargo.lock

@@ -1574,7 +1574,7 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
 [[package]]
 name = "hermes"
-version = "0.4.5"
+version = "0.5.0"
 dependencies = [
  "anyhow",
  "async-trait",

+ 1 - 1
hermes/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name        = "hermes"
-version     = "0.4.5"
+version     = "0.5.0"
 description = "Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle."
 edition     = "2021"
 

+ 5 - 2
hermes/build.rs

@@ -14,12 +14,15 @@ fn main() {
     // directory as a mini-repo with wormhole and googleapis as remotes, so we can copy out the
     // TREEISH paths we want.
     let protobuf_setup = r#"
+        set -euo pipefail
         git init .
         git clean -df
-        git remote add wormhole https://github.com/wormhole-foundation/wormhole.git
-        git remote add googleapis https://github.com/googleapis/googleapis.git
+        git remote add wormhole https://github.com/wormhole-foundation/wormhole.git || true
+        git remote add googleapis https://github.com/googleapis/googleapis.git || true
         git fetch --depth=1 wormhole main
         git fetch --depth=1 googleapis master
+        git reset
+        rm -rf proto/
         git read-tree --prefix=proto/ -u wormhole/main:proto
         git read-tree --prefix=proto/google/api/ -u googleapis/master:google/api
     "#;

+ 1 - 0
hermes/src/api.rs

@@ -122,6 +122,7 @@ pub async fn run(opts: RunOptions, state: ApiState) -> Result<()> {
             rest::latest_vaas,
             rest::price_feed_ids,
             rest::latest_price_updates,
+            rest::timestamp_price_updates,
         ),
         components(
             schemas(

+ 0 - 134
hermes/src/api/benchmarks.rs

@@ -1,134 +0,0 @@
-//! This module communicates with Pyth Benchmarks, an API for historical price feeds and their updates.
-
-use {
-    crate::{
-        aggregate::{
-            PriceFeedUpdate,
-            PriceFeedsWithUpdateData,
-            UnixTimestamp,
-        },
-        api::types::PriceUpdate,
-    },
-    anyhow::Result,
-    base64::{
-        engine::general_purpose::STANDARD as base64_standard_engine,
-        Engine as _,
-    },
-    pyth_sdk::{
-        Price,
-        PriceFeed,
-        PriceIdentifier,
-    },
-    serde::Deserialize,
-};
-
-const BENCHMARKS_REQUEST_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
-
-#[derive(Deserialize, Debug, Clone)]
-enum BlobEncoding {
-    #[serde(rename = "base64")]
-    Base64,
-    #[serde(rename = "hex")]
-    Hex,
-}
-
-#[derive(Deserialize, Debug, Clone)]
-struct BinaryBlob {
-    pub encoding: BlobEncoding,
-    pub data:     Vec<String>,
-}
-
-impl TryFrom<PriceUpdate> for PriceFeedsWithUpdateData {
-    type Error = anyhow::Error;
-    fn try_from(price_update: PriceUpdate) -> Result<Self> {
-        let price_feeds = match price_update.parsed {
-            Some(parsed_updates) => parsed_updates
-                .into_iter()
-                .map(|parsed_price_update| {
-                    Ok(PriceFeedUpdate {
-                        price_feed:        PriceFeed::new(
-                            parsed_price_update.id,
-                            Price {
-                                price:        parsed_price_update.price.price,
-                                conf:         parsed_price_update.price.conf,
-                                expo:         parsed_price_update.price.expo,
-                                publish_time: parsed_price_update.price.publish_time,
-                            },
-                            Price {
-                                price:        parsed_price_update.ema_price.price,
-                                conf:         parsed_price_update.ema_price.conf,
-                                expo:         parsed_price_update.ema_price.expo,
-                                publish_time: parsed_price_update.ema_price.publish_time,
-                            },
-                        ),
-                        slot:              parsed_price_update.metadata.slot,
-                        received_at:       parsed_price_update.metadata.proof_available_time,
-                        update_data:       None, // This field is not available in ParsedPriceUpdate
-                        prev_publish_time: parsed_price_update.metadata.prev_publish_time,
-                    })
-                })
-                .collect::<Result<Vec<_>>>(),
-            None => Err(anyhow::anyhow!("No parsed price updates available")),
-        }?;
-
-        let update_data = price_update
-            .binary
-            .data
-            .iter()
-            .map(|hex_str| hex::decode(hex_str).unwrap_or_default())
-            .collect::<Vec<Vec<u8>>>();
-
-        Ok(PriceFeedsWithUpdateData {
-            price_feeds,
-            update_data,
-        })
-    }
-}
-
-#[async_trait::async_trait]
-pub trait Benchmarks {
-    async fn get_verified_price_feeds(
-        &self,
-        price_ids: &[PriceIdentifier],
-        publish_time: UnixTimestamp,
-    ) -> Result<PriceFeedsWithUpdateData>;
-}
-
-#[async_trait::async_trait]
-impl Benchmarks for crate::state::State {
-    async fn get_verified_price_feeds(
-        &self,
-        price_ids: &[PriceIdentifier],
-        publish_time: UnixTimestamp,
-    ) -> Result<PriceFeedsWithUpdateData> {
-        let endpoint = self
-            .benchmarks_endpoint
-            .as_ref()
-            .ok_or_else(|| anyhow::anyhow!("Benchmarks endpoint is not set"))?
-            .join(&format!("/v1/updates/price/{}", publish_time))
-            .unwrap();
-
-        let client = reqwest::Client::new();
-        let mut request = client
-            .get(endpoint)
-            .timeout(BENCHMARKS_REQUEST_TIMEOUT)
-            .query(&[("encoding", "hex")])
-            .query(&[("parsed", "true")]);
-
-        for price_id in price_ids {
-            request = request.query(&[("ids", price_id)])
-        }
-
-        let response = request.send().await?;
-
-        if response.status() != reqwest::StatusCode::OK {
-            return Err(anyhow::anyhow!(format!(
-                "Price update for price ids {:?} with publish time {} not found in benchmarks. Status code: {}, message: {}",
-                price_ids, publish_time, response.status(), response.text().await?
-            )));
-        }
-
-        let price_update: PriceUpdate = response.json().await?;
-        price_update.try_into()
-    }
-}