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
This commit is contained in:
parent
5dcf5cac4f
commit
22579edc6e
|
@ -1574,7 +1574,7 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|||
|
||||
[[package]]
|
||||
name = "hermes"
|
||||
version = "0.4.5"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
"#;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue