Selaa lähdekoodia

[hermes] Add docs for 1 method (#995)

* doc this one method

* revert
Jayant Krishnamurthy 2 vuotta sitten
vanhempi
sitoutus
07b01118d2
4 muutettua tiedostoa jossa 49 lisäystä ja 34 poistoa
  1. 9 0
      hermes/README.md
  2. 9 11
      hermes/src/api.rs
  3. 15 7
      hermes/src/api/rest.rs
  4. 16 16
      hermes/src/api/types.rs

+ 9 - 0
hermes/README.md

@@ -35,14 +35,23 @@ To set up and run a Hermes node, follow the steps below:
    ```
    This will create a binary in the target/release directory.
 5. **Run the node**: To run Hermes for Pythnet, use the following command:
+
    ```bash
    ./target/release/hermes run \
      --pythnet-http-endpoint https://pythnet-rpc/ \
      --pythnet-ws-endpoint wss://pythnet-rpc/
    ```
+
    Your Hermes node will now start and connect to the specified networks. You
    can interact with the node using the REST and Websocket APIs on port 33999.
 
+   For local development, you can also run the node with cargo watch to restart
+   it automatically when the code changes:
+
+   ```bash
+   cargo watch -w src -x "run -- run --pythnet-http-endpoint https://pythnet.rpcpool.com --pythnet-ws-endpoint wss://pythnet.rpcpool.com"
+   ```
+
 ## Architecture Overview
 
 For users who simply want to run the software, this section can be skipped.

+ 9 - 11
hermes/src/api.rs

@@ -3,24 +3,18 @@ use {
     crate::store::Store,
     anyhow::Result,
     axum::{
+        extract::Extension,
         routing::get,
         Router,
     },
+    serde_qs::axum::QsQueryConfig,
     std::sync::Arc,
     tokio::{
         signal,
         sync::mpsc::Receiver,
     },
     tower_http::cors::CorsLayer,
-    utoipa::{
-        openapi::security::{
-            ApiKey,
-            ApiKeyValue,
-            SecurityScheme,
-        },
-        Modify,
-        OpenApi,
-    },
+    utoipa::OpenApi,
     utoipa_swagger_ui::SwaggerUi,
 };
 
@@ -54,7 +48,7 @@ pub async fn run(store: Arc<Store>, mut update_rx: Receiver<()>, rpc_addr: Strin
       rest::latest_price_feeds,
     ),
     components(
-      schemas(types::RpcPriceFeedMetadata, types::RpcPriceFeed)
+      schemas(types::RpcPriceFeedMetadata, types::RpcPriceFeed, types::PriceIdInput)
     ),
     tags(
       (name = "hermes", description = "Pyth Real-Time Pricing API")
@@ -80,7 +74,11 @@ pub async fn run(store: Arc<Store>, mut update_rx: Receiver<()>, rpc_addr: Strin
         .route("/api/get_vaa_ccip", get(rest::get_vaa_ccip))
         .route("/api/price_feed_ids", get(rest::price_feed_ids))
         .with_state(state.clone())
-        .layer(CorsLayer::permissive()); // Permissive CORS layer to allow all origins
+        // Permissive CORS layer to allow all origins
+        .layer(CorsLayer::permissive())
+        // non-strict mode permits escaped [] in URL parameters.
+        // 5 is the allowed depth (also the default value for this parameter).
+        .layer(Extension(QsQueryConfig::new(false)));
 
 
     // Call dispatch updates to websocket every 1 seconds

+ 15 - 7
hermes/src/api/rest.rs

@@ -97,26 +97,34 @@ pub async fn latest_vaas(
 }
 
 #[derive(Debug, serde::Deserialize, IntoParams)]
+#[into_params(parameter_in=Query)]
 pub struct LatestPriceFeedsQueryParams {
-    #[param(value_type = String)]
+    /// Get the most recent price update for these price feed ids.
+    /// Provide this parameter multiple times to retrieve multiple price updates,
+    /// ids[]=a12...&ids[]=b4c...
+    #[param(
+        rename = "ids[]",
+        example = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
+    )]
     ids:     Vec<PriceIdInput>,
+    /// If true, include the `metadata` field in the response with additional metadata about
+    /// the price update.
     #[serde(default)]
-    #[param(value_type = Option<bool>, required = false, nullable = true)]
     verbose: bool,
+    /// If true, include the binary price update in the `vaa` field of each returned feed.
+    /// This binary data can be submitted to Pyth contracts to update the on-chain price.
     #[serde(default)]
-    #[param(value_type = Option<bool>, required = false, nullable = true)]
     binary:  bool,
 }
 
-/// Get the latest prices by price feed ids.
-///
-/// Get the latest price updates for a provided collection of price feed ids.
+/// Get the latest price updates by price feed id.
 ///
+/// Given a collection of price feed ids, retrieve the latest Pyth price for each price feed.
 #[utoipa::path(
   get,
   path = "/api/latest_price_feeds",
   responses(
-    (status = 200, description = "Price feeds retrieved successfully", body = [Vec<RpcPriceFeed>])
+    (status = 200, description = "Price updates retrieved successfully", body = [Vec<RpcPriceFeed>])
   ),
   params(
     LatestPriceFeedsQueryParams

+ 16 - 16
hermes/src/api/types.rs

@@ -19,23 +19,21 @@ use {
         Price,
         PriceIdentifier,
     },
-    utoipa::{
-        openapi::{
-            RefOr,
-            Schema,
-        },
-        IntoParams,
-        ToSchema,
-    },
+    utoipa::ToSchema,
     wormhole_sdk::Chain,
 };
 
 
-/// PriceIdInput is a wrapper around a 32-byte hex string.
-/// that supports a flexible deserialization from a hex string.
-/// It supports both 0x-prefixed and non-prefixed hex strings,
-/// and also supports both lower and upper case characters.
-#[derive(Debug, Clone, Deref, DerefMut)]
+/// A price id is a 32-byte hex string, optionally prefixed with "0x".
+/// Price ids are case insensitive.
+///
+/// Examples:
+/// * 0x63f341689d98a12ef60a5cff1d7f85c70a9e17bf1575f0e7c0b2512d48b1c8b3
+/// * 63f341689d98a12ef60a5cff1d7f85c70a9e17bf1575f0e7c0b2512d48b1c8b3
+///
+/// See https://pyth.network/developers/price-feed-ids for a list of all price feed ids.
+#[derive(Debug, Clone, Deref, DerefMut, ToSchema)]
+#[schema(value_type=String)]
 pub struct PriceIdInput([u8; 32]);
 // TODO: Use const generics instead of macro.
 impl_deserialize_for_hex_string_wrapper!(PriceIdInput, 32);
@@ -50,15 +48,17 @@ type Base64String = String;
 
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 pub struct RpcPriceFeedMetadata {
-    #[schema(value_type = u64)]
+    #[schema(value_type = u64, example=85480034)]
     pub slot:                       Slot,
+    #[schema(example = 26)]
     pub emitter_chain:              u16,
-    #[schema(value_type = i64)]
+    #[schema(value_type = i64, example=1690576641)]
     pub price_service_receive_time: UnixTimestamp,
 }
 
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 pub struct RpcPriceFeed {
+    #[schema(example = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43")]
     pub id:        PriceIdentifier,
     pub price:     Price,
     pub ema_price: Price,
@@ -66,7 +66,7 @@ pub struct RpcPriceFeed {
     pub metadata:  Option<RpcPriceFeedMetadata>,
     /// Vaa binary represented in base64.
     #[serde(skip_serializing_if = "Option::is_none")]
-    #[schema(value_type = Option<String>)]
+    #[schema(value_type = Option<String>, example="UE5BVQEAAAADuAEAAAADDQC1H7meY5fTed0FsykIb8dt+7nKpbuzfvU2DplDi+dcUl8MC+UIkS65+rkiq+zmNBxE2gaxkBkjdIicZ/fBo+X7AAEqp+WtlWb84np8jJfLpuQ2W+l5KXTigsdAhz5DyVgU3xs+EnaIZxBwcE7EKzjMam+V9rlRy0CGsiQ1kjqqLzfAAQLsoVO0Vu5gVmgc8XGQ7xYhoz36rsBgMjG+e3l/B01esQi/KzPuBf/Ar8Sg5aSEOvEU0muSDb+KIr6d8eEC+FtcAAPZEaBSt4ysXVL84LUcJemQD3SiG30kOfUpF8o7/wI2M2Jf/LyCsbKEQUyLtLbZqnJBSfZJR5AMsrnHDqngMLEGAAY4UDG9GCpRuPvg8hOlsrXuPP3zq7yVPqyG0SG+bNo8rEhP5b1vXlHdG4bZsutX47d5VZ6xnFROKudx3T3/fnWUAQgAU1+kUFc3e0ZZeX1dLRVEryNIVyxMQIcxWwdey+jlIAYowHRM0fJX3Scs80OnT/CERwh5LMlFyU1w578NqxW+AQl2E/9fxjgUTi8crOfDpwsUsmOWw0+Q5OUGhELv/2UZoHAjsaw9OinWUggKACo4SdpPlHYldoWF+J2yGWOW+F4iAQre4c+ocb6a9uSWOnTldFkioqhd9lhmV542+VonCvuy4Tu214NP+2UNd/4Kk3KJCf3iziQJrCBeLi1cLHdLUikgAQtvRFR/nepcF9legl+DywAkUHi5/1MNjlEQvlHyh2XbMiS85yu7/9LgM6Sr+0ukfZY5mSkOcvUkpHn+T+Nw/IrQAQ7lty5luvKUmBpI3ITxSmojJ1aJ0kj/dc0ZcQk+/qo0l0l3/eRLkYjw5j+MZKA8jEubrHzUCke98eSoj8l08+PGAA+DAKNtCwNZe4p6J1Ucod8Lo5RKFfA84CPLVyEzEPQFZ25U9grUK6ilF4GhEia/ndYXLBt3PGW3qa6CBBPM7rH3ABGAyYEtUwzB4CeVedA5o6cKpjRkIebqDNSOqltsr+w7kXdfFVtsK2FMGFZNt5rbpIR+ppztoJ6eOKHmKmi9nQ99ARKkTxRErOs9wJXNHaAuIRV38o1pxRrlQRzGsRuKBqxcQEpC8OPFpyKYcp6iD5l7cO/gRDTamLFyhiUBwKKMP07FAWTEJv8AAAAAABrhAfrtrFhR4yubI7X5QRqMK6xKrj7U3XuBHdGnLqSqcQAAAAAAGp0GAUFVV1YAAAAAAAUYUmIAACcQBsfKUtr4PgZbIXRxRESU79PjE4IBAFUA5i32yLSoX+GmfbRNwS3l2zMPesZrctxliv7fD0pBW0MAAAKqqMJFwAAAAAAqE/NX////+AAAAABkxCb7AAAAAGTEJvoAAAKqIcWxYAAAAAAlR5m4CP/mPsh1IezjYpDlJ4GRb5q4fTs2LjtyO6M0XgVimrIQ4kSh1qg7JKW4gbGkyRntVFR9JO/GNd3FPDit0BK6M+JzXh/h12YNCz9wxlZTvXrNtWNbzqT+91pvl5cphhSPMfAHyEzTPaGR9tKDy9KNu56pmhaY32d2vfEWQmKo22guegeR98oDxs67MmnUraco46a3zEnac2Bm80pasUgMO24=")]
     pub vaa:       Option<Base64String>,
 }