diff --git a/.github/workflows/ci-hermes-client-rust.yml b/.github/workflows/ci-hermes-client-rust.yml new file mode 100644 index 0000000000..76e8bb5a4a --- /dev/null +++ b/.github/workflows/ci-hermes-client-rust.yml @@ -0,0 +1,41 @@ +name: Check Hermes Rust Client + +on: + pull_request: + paths: + - .github/workflows/ci-hermes-client-rust.yml + - apps/hermes/client/rust/** + push: + branches: [main] +jobs: + test: + runs-on: ubuntu-latest + defaults: + run: + working-directory: apps/hermes/client/rust + steps: + - uses: actions/checkout@v2 + - uses: Swatinem/rust-cache@v2 + with: + workspaces: "apps/hermes/client/rust -> target" + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.82.0 + components: rustfmt, clippy + override: true + - name: Format check + run: cargo fmt --all -- --check + if: success() || failure() + - name: Clippy check + run: cargo clippy --tests -- --deny warnings + if: success() || failure() + - name: Build check + run: cargo build + if: success() || failure() + - name: Run tests + run: cargo test + if: success() || failure() + - name: Build examples + run: cargo build --examples + if: success() || failure() diff --git a/.github/workflows/publish-rust-hermes-client.yml b/.github/workflows/publish-rust-hermes-client.yml new file mode 100644 index 0000000000..06f38d0e80 --- /dev/null +++ b/.github/workflows/publish-rust-hermes-client.yml @@ -0,0 +1,18 @@ +name: Publish Rust package hermes-client to crates.io + +on: + push: + tags: + - hermes-client-rust-v* +jobs: + publish-hermes-client: + name: Publish Rust package hermes-client to crates.io + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - run: cargo publish --token ${CARGO_REGISTRY_TOKEN} + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + working-directory: "apps/hermes/client/rust" diff --git a/apps/hermes/client/rust/.openapi-generator-ignore b/apps/hermes/client/rust/.openapi-generator-ignore new file mode 100644 index 0000000000..a09a0d6007 --- /dev/null +++ b/apps/hermes/client/rust/.openapi-generator-ignore @@ -0,0 +1,30 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md + +# Exclude the autogenerated SSE client implementation +# This will be replaced with a custom implementation that properly handles streaming +src/apis/rest_api.rs:price_stream_sse_handler + +# Exclude examples directory to prevent overwriting custom examples +examples/ diff --git a/apps/hermes/client/rust/.openapi-generator/FILES b/apps/hermes/client/rust/.openapi-generator/FILES new file mode 100644 index 0000000000..7453028b61 --- /dev/null +++ b/apps/hermes/client/rust/.openapi-generator/FILES @@ -0,0 +1,46 @@ +.gitignore +.openapi-generator-ignore +.travis.yml +Cargo.toml +README.md +docs/AssetType.md +docs/BinaryUpdate.md +docs/EncodingType.md +docs/GetVaaCcipResponse.md +docs/GetVaaResponse.md +docs/LatestPublisherStakeCapsUpdateDataResponse.md +docs/ParsedPriceFeedTwap.md +docs/ParsedPriceUpdate.md +docs/ParsedPublisherStakeCap.md +docs/ParsedPublisherStakeCapsUpdate.md +docs/PriceFeedMetadata.md +docs/PriceUpdate.md +docs/RestApi.md +docs/RpcPrice.md +docs/RpcPriceFeed.md +docs/RpcPriceFeedMetadata.md +docs/RpcPriceFeedMetadataV2.md +docs/TwapsResponse.md +git_push.sh +src/apis/configuration.rs +src/apis/mod.rs +src/apis/rest_api.rs +src/lib.rs +src/models/asset_type.rs +src/models/binary_update.rs +src/models/encoding_type.rs +src/models/get_vaa_ccip_response.rs +src/models/get_vaa_response.rs +src/models/latest_publisher_stake_caps_update_data_response.rs +src/models/mod.rs +src/models/parsed_price_feed_twap.rs +src/models/parsed_price_update.rs +src/models/parsed_publisher_stake_cap.rs +src/models/parsed_publisher_stake_caps_update.rs +src/models/price_feed_metadata.rs +src/models/price_update.rs +src/models/rpc_price.rs +src/models/rpc_price_feed.rs +src/models/rpc_price_feed_metadata.rs +src/models/rpc_price_feed_metadata_v2.rs +src/models/twaps_response.rs diff --git a/apps/hermes/client/rust/.openapi-generator/VERSION b/apps/hermes/client/rust/.openapi-generator/VERSION new file mode 100644 index 0000000000..eb1dc6a51a --- /dev/null +++ b/apps/hermes/client/rust/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.13.0 diff --git a/apps/hermes/client/rust/Cargo.lock b/apps/hermes/client/rust/Cargo.lock new file mode 100644 index 0000000000..747ee67f8c --- /dev/null +++ b/apps/hermes/client/rust/Cargo.lock @@ -0,0 +1,1973 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "eventsource-stream" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" +dependencies = [ + "futures-core", + "nom", + "pin-project-lite", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" + +[[package]] +name = "hermes-client" +version = "0.1.0" +dependencies = [ + "anyhow", + "base64", + "derive_more", + "eventsource-stream", + "futures-util", + "reqwest", + "serde", + "serde_json", + "serde_repr", + "serde_with", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 0.26.11", +] + +[[package]] +name = "hyper-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.3", + "serde", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quinn" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags", +] + +[[package]] +name = "reqwest" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots 0.26.11", + "windows-registry", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustls" +version = "0.23.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.9.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.0", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings 0.4.0", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +dependencies = [ + "windows-result", + "windows-strings 0.3.1", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/apps/hermes/client/rust/Cargo.toml b/apps/hermes/client/rust/Cargo.toml new file mode 100644 index 0000000000..e0d6651fc5 --- /dev/null +++ b/apps/hermes/client/rust/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "hermes-client" +version = "0.1.0" +authors = ["Pyth Network Contributors"] +description = "A Rust client for Pyth Hermes price service" +license = "Apache-2.0" +edition = "2021" +repository = "https://github.com/pyth-network/pyth-crosschain" +documentation = "https://docs.rs/hermes-client" +readme = "README.md" +keywords = ["pyth", "price", "oracle", "defi", "finance"] +categories = ["api-bindings", "finance"] + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_with = { version = "3.8", default-features = false, features = ["base64", "std", "macros"] } +serde_json = "1.0" +serde_repr = "0.1" +url = "2.5" +reqwest = { version = "0.12", default-features = false, features = ["json", "multipart", "rustls-tls", "stream"] } +tokio = { version = "1.0", features = ["full"] } +tokio-stream = { version = "0.1", features = ["sync"] } +anyhow = "1.0" +futures-util = "0.3" +derive_more = { version = "1.0.0", features = ["from"] } +base64 = "0.22.1" +tracing = "0.1" +eventsource-stream = "0.2.3" + +[[example]] +name = "latest_prices" +path = "examples/latest_prices.rs" + +[[example]] +name = "price_stream" +path = "examples/price_stream.rs" diff --git a/apps/hermes/client/rust/README.md b/apps/hermes/client/rust/README.md new file mode 100644 index 0000000000..6d79381268 --- /dev/null +++ b/apps/hermes/client/rust/README.md @@ -0,0 +1,143 @@ +# Hermes Rust Client + +A Rust client for interacting with the Pyth Network's real-time pricing data through the Hermes service. + +## Description + +This package provides a Rust client for the Hermes service, which serves Pyth price feeds. It allows you to easily fetch price feeds and subscribe to real-time price updates. + +## Installation + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +hermes-client = "0.1.0" +``` + +## Usage + +```rust +use hermes_client::apis::rest_api; +use hermes_client::apis::configuration::Configuration; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create a new configuration with the Hermes endpoint + let mut config = Configuration::new(); + config.base_path = "https://hermes.pyth.network".to_string(); + + // Fetch latest price updates for a specific price feed + let price_feed_id = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; + let price_updates = rest_api::latest_price_updates(&config, Some(&[price_feed_id]), None, None).await?; + println!("Price updates: {:?}", price_updates); + + Ok(()) +} +``` + +## Examples + +The package includes example applications that demonstrate how to use the client: + +### Fetching Latest Prices + +This example fetches and displays the latest prices for BTC/USD and ETH/USD: + +```bash +cargo run --example latest_prices +``` + +### Streaming Price Updates + +This example demonstrates how to subscribe to a real-time stream of price updates for BTC/USD and ETH/USD: + +```bash +cargo run --example price_stream +``` + +To run the examples, clone the repository and execute the commands from the `apps/hermes/client/rust` directory. + +## API Documentation + +For detailed API documentation, you can generate the documentation locally: + +```bash +cargo doc --open +``` + +The client provides access to all Hermes API endpoints, including: + +- Fetching latest price updates +- Getting price feed metadata +- Retrieving TWAPs (Time-Weighted Average Prices) +- Accessing publisher stake caps +- Streaming real-time price updates + +## Code Generation + +This client was generated from the [Hermes OpenAPI specification](https://hermes.pyth.network/docs/openapi.json) using the OpenAPI Generator tool. + +### Regeneration Steps + +To regenerate the client after updates to the Hermes API: + +1. Install OpenAPI Generator CLI: + ```bash + npm install @openapitools/openapi-generator-cli -g + ``` + +2. Generate the client: + ```bash + npx @openapitools/openapi-generator-cli generate \ + -i https://hermes.pyth.network/docs/openapi.json \ + -g rust \ + -o apps/hermes/client/rust \ + --additional-properties=packageName=hermes-client,packageVersion=0.1.0 + ``` + +3. Manually update dependencies in Cargo.toml and version number if necessary. + +4. Create a `.openapi-generator-ignore` file to preserve custom implementations: + ```bash + echo "src/streaming.rs" > .openapi-generator-ignore + echo "examples/" >> .openapi-generator-ignore + ``` + +5. Implement custom streaming functionality in `src/streaming.rs` using the `eventsource-stream` crate for proper SSE handling. + +6. Rename parameter names in the generated code to be more intuitive (e.g., in `rest_api.rs`). + +7. Fix formatting and clippy linting issues: + ```bash + cargo fmt + cargo clippy --fix + ``` + +## Publishing + +This package is published to crates.io when a new tag matching `hermes-client-rust-v*` is pushed. + +## Hermes Public Endpoint + +The client defaults to using the Hermes public endpoint at https://hermes.pyth.network. For production applications, we recommend using a dedicated endpoint for better reliability. + +## Documentation For Models + + - [AssetType](docs/AssetType.md) + - [BinaryUpdate](docs/BinaryUpdate.md) + - [EncodingType](docs/EncodingType.md) + - [GetVaaCcipResponse](docs/GetVaaCcipResponse.md) + - [GetVaaResponse](docs/GetVaaResponse.md) + - [LatestPublisherStakeCapsUpdateDataResponse](docs/LatestPublisherStakeCapsUpdateDataResponse.md) + - [ParsedPriceFeedTwap](docs/ParsedPriceFeedTwap.md) + - [ParsedPriceUpdate](docs/ParsedPriceUpdate.md) + - [ParsedPublisherStakeCap](docs/ParsedPublisherStakeCap.md) + - [ParsedPublisherStakeCapsUpdate](docs/ParsedPublisherStakeCapsUpdate.md) + - [PriceFeedMetadata](docs/PriceFeedMetadata.md) + - [PriceUpdate](docs/PriceUpdate.md) + - [RpcPrice](docs/RpcPrice.md) + - [RpcPriceFeed](docs/RpcPriceFeed.md) + - [RpcPriceFeedMetadata](docs/RpcPriceFeedMetadata.md) + - [RpcPriceFeedMetadataV2](docs/RpcPriceFeedMetadataV2.md) + - [TwapsResponse](docs/TwapsResponse.md) diff --git a/apps/hermes/client/rust/docs/AssetType.md b/apps/hermes/client/rust/docs/AssetType.md new file mode 100644 index 0000000000..c1abcd38d4 --- /dev/null +++ b/apps/hermes/client/rust/docs/AssetType.md @@ -0,0 +1,15 @@ +# AssetType + +## Enum Variants + +| Name | Value | +|---- | -----| +| Crypto | crypto | +| Fx | fx | +| Equity | equity | +| Metal | metal | +| Rates | rates | +| CryptoRedemptionRate | crypto_redemption_rate | + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/BinaryUpdate.md b/apps/hermes/client/rust/docs/BinaryUpdate.md new file mode 100644 index 0000000000..38de3a500f --- /dev/null +++ b/apps/hermes/client/rust/docs/BinaryUpdate.md @@ -0,0 +1,10 @@ +# BinaryUpdate + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**data** | **Vec** | | +**encoding** | [**models::EncodingType**](EncodingType.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/EncodingType.md b/apps/hermes/client/rust/docs/EncodingType.md new file mode 100644 index 0000000000..6fb7dee9dd --- /dev/null +++ b/apps/hermes/client/rust/docs/EncodingType.md @@ -0,0 +1,11 @@ +# EncodingType + +## Enum Variants + +| Name | Value | +|---- | -----| +| Hex | hex | +| Base64 | base64 | + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/GetVaaCcipResponse.md b/apps/hermes/client/rust/docs/GetVaaCcipResponse.md new file mode 100644 index 0000000000..4e803a6ded --- /dev/null +++ b/apps/hermes/client/rust/docs/GetVaaCcipResponse.md @@ -0,0 +1,9 @@ +# GetVaaCcipResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**data** | **String** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/GetVaaResponse.md b/apps/hermes/client/rust/docs/GetVaaResponse.md new file mode 100644 index 0000000000..f03e3858c0 --- /dev/null +++ b/apps/hermes/client/rust/docs/GetVaaResponse.md @@ -0,0 +1,10 @@ +# GetVaaResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**publish_time** | **i64** | | +**vaa** | **String** | The VAA binary represented as a base64 string. | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/LatestPublisherStakeCapsUpdateDataResponse.md b/apps/hermes/client/rust/docs/LatestPublisherStakeCapsUpdateDataResponse.md new file mode 100644 index 0000000000..74430ed2ff --- /dev/null +++ b/apps/hermes/client/rust/docs/LatestPublisherStakeCapsUpdateDataResponse.md @@ -0,0 +1,10 @@ +# LatestPublisherStakeCapsUpdateDataResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**binary** | [**models::BinaryUpdate**](BinaryUpdate.md) | | +**parsed** | Option<[**Vec**](ParsedPublisherStakeCapsUpdate.md)> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/ParsedPriceFeedTwap.md b/apps/hermes/client/rust/docs/ParsedPriceFeedTwap.md new file mode 100644 index 0000000000..c5c193f777 --- /dev/null +++ b/apps/hermes/client/rust/docs/ParsedPriceFeedTwap.md @@ -0,0 +1,13 @@ +# ParsedPriceFeedTwap + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**down_slots_ratio** | **String** | The % of slots where the network was down over the TWAP window. A value of zero indicates no slots were missed over the window, and a value of one indicates that every slot was missed over the window. This is a float value stored as a string to avoid precision loss. | +**end_timestamp** | **i64** | The end unix timestamp of the window | +**id** | **String** | | +**start_timestamp** | **i64** | The start unix timestamp of the window | +**twap** | [**models::RpcPrice**](RpcPrice.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/ParsedPriceUpdate.md b/apps/hermes/client/rust/docs/ParsedPriceUpdate.md new file mode 100644 index 0000000000..aa87b6a473 --- /dev/null +++ b/apps/hermes/client/rust/docs/ParsedPriceUpdate.md @@ -0,0 +1,12 @@ +# ParsedPriceUpdate + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ema_price** | [**models::RpcPrice**](RpcPrice.md) | | +**id** | **String** | | +**metadata** | [**models::RpcPriceFeedMetadataV2**](RpcPriceFeedMetadataV2.md) | | +**price** | [**models::RpcPrice**](RpcPrice.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/ParsedPublisherStakeCap.md b/apps/hermes/client/rust/docs/ParsedPublisherStakeCap.md new file mode 100644 index 0000000000..4c845d4a4e --- /dev/null +++ b/apps/hermes/client/rust/docs/ParsedPublisherStakeCap.md @@ -0,0 +1,10 @@ +# ParsedPublisherStakeCap + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**cap** | **i64** | | +**publisher** | **String** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/ParsedPublisherStakeCapsUpdate.md b/apps/hermes/client/rust/docs/ParsedPublisherStakeCapsUpdate.md new file mode 100644 index 0000000000..7f97193cf4 --- /dev/null +++ b/apps/hermes/client/rust/docs/ParsedPublisherStakeCapsUpdate.md @@ -0,0 +1,9 @@ +# ParsedPublisherStakeCapsUpdate + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**publisher_stake_caps** | [**Vec**](ParsedPublisherStakeCap.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/PriceFeedMetadata.md b/apps/hermes/client/rust/docs/PriceFeedMetadata.md new file mode 100644 index 0000000000..4e68af1f1d --- /dev/null +++ b/apps/hermes/client/rust/docs/PriceFeedMetadata.md @@ -0,0 +1,10 @@ +# PriceFeedMetadata + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**attributes** | **std::collections::HashMap** | | +**id** | **String** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/PriceUpdate.md b/apps/hermes/client/rust/docs/PriceUpdate.md new file mode 100644 index 0000000000..1162701b80 --- /dev/null +++ b/apps/hermes/client/rust/docs/PriceUpdate.md @@ -0,0 +1,10 @@ +# PriceUpdate + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**binary** | [**models::BinaryUpdate**](BinaryUpdate.md) | | +**parsed** | Option<[**Vec**](ParsedPriceUpdate.md)> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/RestApi.md b/apps/hermes/client/rust/docs/RestApi.md new file mode 100644 index 0000000000..8915a8552a --- /dev/null +++ b/apps/hermes/client/rust/docs/RestApi.md @@ -0,0 +1,400 @@ +# \RestApi + +All URIs are relative to *http://localhost* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**get_price_feed**](RestApi.md#get_price_feed) | **GET** /api/get_price_feed | **Deprecated: use /v2/updates/price/{publish_time} instead** +[**get_vaa**](RestApi.md#get_vaa) | **GET** /api/get_vaa | **Deprecated: use /v2/updates/price/{publish_time} instead** +[**get_vaa_ccip**](RestApi.md#get_vaa_ccip) | **GET** /api/get_vaa_ccip | **Deprecated: use /v2/updates/price/{publish_time} instead** +[**latest_price_feeds**](RestApi.md#latest_price_feeds) | **GET** /api/latest_price_feeds | **Deprecated: use /v2/updates/price/latest instead** +[**latest_price_updates**](RestApi.md#latest_price_updates) | **GET** /v2/updates/price/latest | Get the latest price updates by price feed id. +[**latest_publisher_stake_caps**](RestApi.md#latest_publisher_stake_caps) | **GET** /v2/updates/publisher_stake_caps/latest | Get the most recent publisher stake caps update data. +[**latest_twaps**](RestApi.md#latest_twaps) | **GET** /v2/updates/twap/{window_seconds}/latest | Get the latest TWAP by price feed id with a custom time window. +[**latest_vaas**](RestApi.md#latest_vaas) | **GET** /api/latest_vaas | **Deprecated: use /v2/updates/price/latest instead** +[**price_feed_ids**](RestApi.md#price_feed_ids) | **GET** /api/price_feed_ids | **Deprecated: use /v2/price_feeds instead** +[**price_feeds_metadata**](RestApi.md#price_feeds_metadata) | **GET** /v2/price_feeds | Get the set of price feeds. +[**price_stream_sse_handler**](RestApi.md#price_stream_sse_handler) | **GET** /v2/updates/price/stream | SSE route handler for streaming price updates. +[**timestamp_price_updates**](RestApi.md#timestamp_price_updates) | **GET** /v2/updates/price/{publish_time} | Get the latest price updates by price feed id. + + + +## get_price_feed + +> models::RpcPriceFeed get_price_feed(id, publish_time, verbose, binary) +**Deprecated: use /v2/updates/price/{publish_time} instead** + +**Deprecated: use /v2/updates/price/{publish_time} instead** Get a price update for a price feed with a specific timestamp Given a price feed id and timestamp, retrieve the Pyth price update closest to that timestamp. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**id** | **String** | The id of the price feed to get an update for. | [required] | +**publish_time** | **i64** | The unix timestamp in seconds. This endpoint will return the first update whose publish_time is >= the provided value. | [required] | +**verbose** | Option<**bool**> | If true, include the `metadata` field in the response with additional metadata about the price update. | | +**binary** | Option<**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. | | + +### Return type + +[**models::RpcPriceFeed**](RpcPriceFeed.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_vaa + +> models::GetVaaResponse get_vaa(id, publish_time) +**Deprecated: use /v2/updates/price/{publish_time} instead** + +**Deprecated: use /v2/updates/price/{publish_time} instead** Get a VAA for a price feed with a specific timestamp Given a price feed id and timestamp, retrieve the Pyth price update closest to that timestamp. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**id** | **String** | The ID of the price feed to get an update for. | [required] | +**publish_time** | **i64** | The unix timestamp in seconds. This endpoint will return the first update whose publish_time is >= the provided value. | [required] | + +### Return type + +[**models::GetVaaResponse**](GetVaaResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json, text/plain + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_vaa_ccip + +> models::GetVaaCcipResponse get_vaa_ccip(data) +**Deprecated: use /v2/updates/price/{publish_time} instead** + +**Deprecated: use /v2/updates/price/{publish_time} instead** Get a VAA for a price feed using CCIP This endpoint accepts a single argument which is a hex-encoded byte string of the following form: ` ` + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**data** | **std::path::PathBuf** | | [required] | + +### Return type + +[**models::GetVaaCcipResponse**](GetVaaCcipResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## latest_price_feeds + +> Vec latest_price_feeds(ids_left_square_bracket_right_square_bracket, verbose, binary) +**Deprecated: use /v2/updates/price/latest instead** + +**Deprecated: use /v2/updates/price/latest instead** 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. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**ids_left_square_bracket_right_square_bracket** | [**Vec**](String.md) | Get the most recent price update for this set of price feed ids. This parameter can be provided multiple times to retrieve multiple price updates, for example see the following query string: ``` ?ids[]=a12...&ids[]=b4c... ``` | [required] | +**verbose** | Option<**bool**> | If true, include the `metadata` field in the response with additional metadata about the price update. | | +**binary** | Option<**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. | | + +### Return type + +[**Vec**](RpcPriceFeed.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## latest_price_updates + +> models::PriceUpdate latest_price_updates(ids_left_square_bracket_right_square_bracket, encoding, parsed, ignore_invalid_price_ids) +Get the latest price updates by price feed id. + +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. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**ids_left_square_bracket_right_square_bracket** | [**Vec**](String.md) | Get the most recent price update for this set of price feed ids. This parameter can be provided multiple times to retrieve multiple price updates, for example see the following query string: ``` ?ids[]=a12...&ids[]=b4c... ``` | [required] | +**encoding** | Option<[**EncodingType**](.md)> | Optional encoding type. If true, return the price update in the encoding specified by the encoding parameter. Default is `hex`. | | +**parsed** | Option<**bool**> | If true, include the parsed price update in the `parsed` field of each returned feed. Default is `true`. | | +**ignore_invalid_price_ids** | Option<**bool**> | If true, invalid price IDs in the `ids` parameter are ignored. Only applicable to the v2 APIs. Default is `false`. | | + +### Return type + +[**models::PriceUpdate**](PriceUpdate.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json, text/plain + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## latest_publisher_stake_caps + +> models::LatestPublisherStakeCapsUpdateDataResponse latest_publisher_stake_caps(encoding, parsed) +Get the most recent publisher stake caps update data. + +Get the most recent publisher stake caps update data. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**encoding** | Option<[**EncodingType**](.md)> | Get the most recent publisher stake caps update data. Optional encoding type. If true, return the message in the encoding specified by the encoding parameter. Default is `hex`. | | +**parsed** | Option<**bool**> | If true, include the parsed update in the `parsed` field of each returned feed. Default is `true`. | | + +### Return type + +[**models::LatestPublisherStakeCapsUpdateDataResponse**](LatestPublisherStakeCapsUpdateDataResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## latest_twaps + +> models::TwapsResponse latest_twaps(window_seconds, ids_left_square_bracket_right_square_bracket, encoding, parsed, ignore_invalid_price_ids) +Get the latest TWAP by price feed id with a custom time window. + +Get the latest TWAP by price feed id with a custom time window. Given a collection of price feed ids, retrieve the latest Pyth TWAP price for each price feed. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**window_seconds** | **i64** | The time window in seconds over which to calculate the TWAP, ending at the current time. For example, a value of 300 would return the most recent 5 minute TWAP. Must be greater than 0 and less than or equal to 600 seconds (10 minutes). | [required] | +**ids_left_square_bracket_right_square_bracket** | [**Vec**](String.md) | Get the most recent TWAP (time weighted average price) for this set of price feed ids. The `binary` data contains the signed start & end cumulative price updates needed to calculate the TWAPs on-chain. The `parsed` data contains the calculated TWAPs. This parameter can be provided multiple times to retrieve multiple price updates, for example see the following query string: ``` ?ids[]=a12...&ids[]=b4c... ``` | [required] | +**encoding** | Option<[**EncodingType**](.md)> | Optional encoding type. If true, return the cumulative price updates in the encoding specified by the encoding parameter. Default is `hex`. | | +**parsed** | Option<**bool**> | If true, include the calculated TWAP in the `parsed` field of each returned feed. Default is `true`. | | +**ignore_invalid_price_ids** | Option<**bool**> | If true, invalid price IDs in the `ids` parameter are ignored. Only applicable to the v2 APIs. Default is `false`. | | + +### Return type + +[**models::TwapsResponse**](TwapsResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json, text/plain + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## latest_vaas + +> Vec latest_vaas(ids_left_square_bracket_right_square_bracket) +**Deprecated: use /v2/updates/price/latest instead** + +**Deprecated: use /v2/updates/price/latest instead** Get VAAs for a set of price feed ids. Given a collection of price feed ids, retrieve the latest VAA for each. The returned VAA(s) can be submitted to the Pyth contract to update the on-chain price. If VAAs are not found for every provided price ID the call will fail. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**ids_left_square_bracket_right_square_bracket** | [**Vec**](String.md) | Get the VAAs for this set of price feed ids. This parameter can be provided multiple times to retrieve multiple price updates, for example see the following query string: ``` ?ids[]=a12...&ids[]=b4c... ``` | [required] | + +### Return type + +**Vec** + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## price_feed_ids + +> Vec price_feed_ids() +**Deprecated: use /v2/price_feeds instead** + +**Deprecated: use /v2/price_feeds instead** Get the set of price feed IDs. This endpoint fetches all of the price feed IDs for which price updates can be retrieved. + +### Parameters + +This endpoint does not need any parameter. + +### Return type + +**Vec** + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## price_feeds_metadata + +> Vec price_feeds_metadata(query, asset_type) +Get the set of price feeds. + +Get the set of price feeds. This endpoint fetches all price feeds from the Pyth network. It can be filtered by asset type and query string. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**query** | Option<**String**> | Optional query parameter. If provided, the results will be filtered to all price feeds whose symbol contains the query string. Query string is case insensitive. | | +**asset_type** | Option<[**models::AssetType**](.md)> | Optional query parameter. If provided, the results will be filtered by asset type. Possible values are crypto, equity, fx, metal, rates. Filter string is case insensitive. | | + +### Return type + +[**Vec**](PriceFeedMetadata.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## price_stream_sse_handler + +> models::PriceUpdate price_stream_sse_handler(ids_left_square_bracket_right_square_bracket, encoding, parsed, allow_unordered, benchmarks_only, ignore_invalid_price_ids) +SSE route handler for streaming price updates. + +SSE route handler for streaming price updates. The connection will automatically close after 24 hours to prevent resource leaks. Clients should implement reconnection logic to maintain continuous price updates. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**ids_left_square_bracket_right_square_bracket** | [**Vec**](String.md) | Get the most recent price update for this set of price feed ids. This parameter can be provided multiple times to retrieve multiple price updates, for example see the following query string: ``` ?ids[]=a12...&ids[]=b4c... ``` | [required] | +**encoding** | Option<[**EncodingType**](.md)> | Optional encoding type. If true, return the price update in the encoding specified by the encoding parameter. Default is `hex`. | | +**parsed** | Option<**bool**> | If true, include the parsed price update in the `parsed` field of each returned feed. Default is `true`. | | +**allow_unordered** | Option<**bool**> | If true, allows unordered price updates to be included in the stream. | | +**benchmarks_only** | Option<**bool**> | If true, only include benchmark prices that are the initial price updates at a given timestamp (i.e., prevPubTime != pubTime). | | +**ignore_invalid_price_ids** | Option<**bool**> | If true, invalid price IDs in the `ids` parameter are ignored. Only applicable to the v2 APIs. Default is `false`. | | + +### Return type + +[**models::PriceUpdate**](PriceUpdate.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json, text/plain + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## timestamp_price_updates + +> models::PriceUpdate timestamp_price_updates(publish_time, ids_left_square_bracket_right_square_bracket, encoding, parsed, ignore_invalid_price_ids) +Get the latest price updates by price feed id. + +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. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**publish_time** | **i64** | The unix timestamp in seconds. This endpoint will return the first update whose publish_time is >= the provided value. | [required] | +**ids_left_square_bracket_right_square_bracket** | [**Vec**](String.md) | Get the most recent price update for this set of price feed ids. This parameter can be provided multiple times to retrieve multiple price updates, for example see the following query string: ``` ?ids[]=a12...&ids[]=b4c... ``` | [required] | +**encoding** | Option<[**EncodingType**](.md)> | Optional encoding type. If true, return the price update in the encoding specified by the encoding parameter. Default is `hex`. | | +**parsed** | Option<**bool**> | If true, include the parsed price update in the `parsed` field of each returned feed. Default is `true`. | | +**ignore_invalid_price_ids** | Option<**bool**> | If true, invalid price IDs in the `ids` parameter are ignored. Only applicable to the v2 APIs. Default is `false`. | | + +### Return type + +[**models::PriceUpdate**](PriceUpdate.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json, text/plain + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/RpcPrice.md b/apps/hermes/client/rust/docs/RpcPrice.md new file mode 100644 index 0000000000..2f4dd442a5 --- /dev/null +++ b/apps/hermes/client/rust/docs/RpcPrice.md @@ -0,0 +1,12 @@ +# RpcPrice + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**conf** | **String** | The confidence interval associated with the price, stored as a string to avoid precision loss | +**expo** | **i32** | The exponent associated with both the price and confidence interval. Multiply those values by `10^expo` to get the real value. | +**price** | **String** | The price itself, stored as a string to avoid precision loss | +**publish_time** | **i64** | When the price was published. The `publish_time` is a unix timestamp, i.e., the number of seconds since the Unix epoch (00:00:00 UTC on 1 Jan 1970). | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/RpcPriceFeed.md b/apps/hermes/client/rust/docs/RpcPriceFeed.md new file mode 100644 index 0000000000..0f44398efa --- /dev/null +++ b/apps/hermes/client/rust/docs/RpcPriceFeed.md @@ -0,0 +1,13 @@ +# RpcPriceFeed + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ema_price** | [**models::RpcPrice**](RpcPrice.md) | | +**id** | **String** | | +**metadata** | Option<[**models::RpcPriceFeedMetadata**](RpcPriceFeedMetadata.md)> | | [optional] +**price** | [**models::RpcPrice**](RpcPrice.md) | | +**vaa** | Option<**String**> | The VAA binary represented as a base64 string. | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/RpcPriceFeedMetadata.md b/apps/hermes/client/rust/docs/RpcPriceFeedMetadata.md new file mode 100644 index 0000000000..5f3f15b958 --- /dev/null +++ b/apps/hermes/client/rust/docs/RpcPriceFeedMetadata.md @@ -0,0 +1,12 @@ +# RpcPriceFeedMetadata + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**emitter_chain** | **i32** | | +**prev_publish_time** | Option<**i64**> | | [optional] +**price_service_receive_time** | Option<**i64**> | | [optional] +**slot** | Option<**i64**> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/RpcPriceFeedMetadataV2.md b/apps/hermes/client/rust/docs/RpcPriceFeedMetadataV2.md new file mode 100644 index 0000000000..fd97b3da2c --- /dev/null +++ b/apps/hermes/client/rust/docs/RpcPriceFeedMetadataV2.md @@ -0,0 +1,11 @@ +# RpcPriceFeedMetadataV2 + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**prev_publish_time** | Option<**i64**> | | [optional] +**proof_available_time** | Option<**i64**> | | [optional] +**slot** | Option<**i64**> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/docs/TwapsResponse.md b/apps/hermes/client/rust/docs/TwapsResponse.md new file mode 100644 index 0000000000..1bf41ed3bf --- /dev/null +++ b/apps/hermes/client/rust/docs/TwapsResponse.md @@ -0,0 +1,10 @@ +# TwapsResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**binary** | [**models::BinaryUpdate**](BinaryUpdate.md) | | +**parsed** | Option<[**Vec**](ParsedPriceFeedTwap.md)> | The calculated TWAPs for each price ID | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/apps/hermes/client/rust/examples/latest_prices.rs b/apps/hermes/client/rust/examples/latest_prices.rs new file mode 100644 index 0000000000..aa06c3491f --- /dev/null +++ b/apps/hermes/client/rust/examples/latest_prices.rs @@ -0,0 +1,51 @@ +use hermes_client::apis::configuration::Configuration; +use hermes_client::apis::rest_api; +use hermes_client::models::EncodingType; +use std::error::Error; + +const BTC_PRICE_FEED_ID: &str = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; +const ETH_PRICE_FEED_ID: &str = "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut config = Configuration::new(); + config.base_path = "https://hermes.pyth.network".to_string(); + + let price_feed_ids = vec![BTC_PRICE_FEED_ID.to_string(), ETH_PRICE_FEED_ID.to_string()]; + + let price_update = rest_api::latest_price_updates( + &config, + price_feed_ids, + Some(EncodingType::Base64), + Some(true), // parsed + Some(false), // ignore_invalid_price_ids + ) + .await?; + + println!("Latest Price Updates:"); + println!("===================="); + + if let Some(Some(parsed_updates)) = price_update.parsed { + for update in parsed_updates { + let price_feed_id = update.id; + let symbol = match price_feed_id.as_str() { + BTC_PRICE_FEED_ID => "BTC/USD", + ETH_PRICE_FEED_ID => "ETH/USD", + _ => "Unknown", + }; + + let price = &update.price; + let price_value = price.price.parse::().unwrap_or(0.0) * 10f64.powi(price.expo); + let conf_value = price.conf.parse::().unwrap_or(0.0) * 10f64.powi(price.expo); + + println!( + "{}: ${:.2} (conf: ${:.2}, publish_time: {})", + symbol, price_value, conf_value, price.publish_time + ); + } + } else { + println!("No parsed price data available"); + } + + Ok(()) +} diff --git a/apps/hermes/client/rust/examples/price_stream.rs b/apps/hermes/client/rust/examples/price_stream.rs new file mode 100644 index 0000000000..69fb2cc68c --- /dev/null +++ b/apps/hermes/client/rust/examples/price_stream.rs @@ -0,0 +1,57 @@ +use futures_util::stream::StreamExt; +use hermes_client::create_price_update_stream; +use hermes_client::Configuration; +use std::error::Error; + +const BTC_PRICE_FEED_ID: &str = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; +const ETH_PRICE_FEED_ID: &str = "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut config = Configuration::new(); + config.base_path = "https://hermes.pyth.network".to_string(); + + let price_feed_ids = vec![BTC_PRICE_FEED_ID.to_string(), ETH_PRICE_FEED_ID.to_string()]; + + println!("Starting SSE price stream for BTC/USD and ETH/USD..."); + println!("Press Ctrl+C to exit"); + println!("===================="); + + let mut stream = create_price_update_stream( + &config, + price_feed_ids, + None, // default encoding (base64) + None, // default allow_unordered + None, // default benchmarks_only + None, // default ignore_invalid_price_ids + ) + .await?; + + while let Some(result) = stream.next().await { + match result { + Ok(update) => { + let price_feed_id = &update.id; + let symbol = match price_feed_id.as_str() { + BTC_PRICE_FEED_ID => "BTC/USD", + ETH_PRICE_FEED_ID => "ETH/USD", + _ => "Unknown", + }; + + let price = &update.price; + let price_value = + price.price.parse::().unwrap_or(0.0) * 10f64.powi(price.expo); + let conf_value = price.conf.parse::().unwrap_or(0.0) * 10f64.powi(price.expo); + + println!( + "{}: ${:.2} (conf: ${:.2}, publish_time: {})", + symbol, price_value, conf_value, price.publish_time + ); + } + Err(e) => { + eprintln!("Error: {}", e); + } + } + } + + Ok(()) +} diff --git a/apps/hermes/client/rust/src/apis/configuration.rs b/apps/hermes/client/rust/src/apis/configuration.rs new file mode 100644 index 0000000000..743605e423 --- /dev/null +++ b/apps/hermes/client/rust/src/apis/configuration.rs @@ -0,0 +1,48 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +#[derive(Debug, Clone)] +pub struct Configuration { + pub base_path: String, + pub user_agent: Option, + pub client: reqwest::Client, + pub basic_auth: Option, + pub oauth_access_token: Option, + pub bearer_access_token: Option, + pub api_key: Option, +} + +pub type BasicAuth = (String, Option); + +#[derive(Debug, Clone)] +pub struct ApiKey { + pub prefix: Option, + pub key: String, +} + +impl Configuration { + pub fn new() -> Configuration { + Configuration::default() + } +} + +impl Default for Configuration { + fn default() -> Self { + Configuration { + base_path: "http://localhost".to_owned(), + user_agent: Some("OpenAPI-Generator/0.8.6/rust".to_owned()), + client: reqwest::Client::new(), + basic_auth: None, + oauth_access_token: None, + bearer_access_token: None, + api_key: None, + } + } +} diff --git a/apps/hermes/client/rust/src/apis/mod.rs b/apps/hermes/client/rust/src/apis/mod.rs new file mode 100644 index 0000000000..06d5976bc8 --- /dev/null +++ b/apps/hermes/client/rust/src/apis/mod.rs @@ -0,0 +1,118 @@ +use std::error; +use std::fmt; + +#[derive(Debug, Clone)] +pub struct ResponseContent { + pub status: reqwest::StatusCode, + pub content: String, + pub entity: Option, +} + +#[derive(Debug)] +pub enum Error { + Reqwest(reqwest::Error), + Serde(serde_json::Error), + Io(std::io::Error), + ResponseError(ResponseContent), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (module, e) = match self { + Error::Reqwest(e) => ("reqwest", e.to_string()), + Error::Serde(e) => ("serde", e.to_string()), + Error::Io(e) => ("IO", e.to_string()), + Error::ResponseError(e) => ("response", format!("status code {}", e.status)), + }; + write!(f, "error in {}: {}", module, e) + } +} + +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(match self { + Error::Reqwest(e) => e, + Error::Serde(e) => e, + Error::Io(e) => e, + Error::ResponseError(_) => return None, + }) + } +} + +impl From for Error { + fn from(e: reqwest::Error) -> Self { + Error::Reqwest(e) + } +} + +impl From for Error { + fn from(e: serde_json::Error) -> Self { + Error::Serde(e) + } +} + +impl From for Error { + fn from(e: std::io::Error) -> Self { + Error::Io(e) + } +} + +pub fn urlencode>(s: T) -> String { + ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes()).collect() +} + +pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String, String)> { + if let serde_json::Value::Object(object) = value { + let mut params = vec![]; + + for (key, value) in object { + match value { + serde_json::Value::Object(_) => params.append(&mut parse_deep_object( + &format!("{}[{}]", prefix, key), + value, + )), + serde_json::Value::Array(array) => { + for (i, value) in array.iter().enumerate() { + params.append(&mut parse_deep_object( + &format!("{}[{}][{}]", prefix, key, i), + value, + )); + } + } + serde_json::Value::String(s) => { + params.push((format!("{}[{}]", prefix, key), s.clone())) + } + _ => params.push((format!("{}[{}]", prefix, key), value.to_string())), + } + } + + return params; + } + + unimplemented!("Only objects are supported with style=deepObject") +} + +/// Internal use only +/// A content type supported by this client. +#[allow(dead_code)] +enum ContentType { + Json, + Text, + Unsupported(String), +} + +impl From<&str> for ContentType { + fn from(content_type: &str) -> Self { + if content_type.starts_with("application") && content_type.contains("json") { + Self::Json + } else if content_type.starts_with("text/plain") { + Self::Text + } else { + Self::Unsupported(content_type.to_string()) + } + } +} + +pub mod rest_api; + +pub mod configuration; diff --git a/apps/hermes/client/rust/src/apis/rest_api.rs b/apps/hermes/client/rust/src/apis/rest_api.rs new file mode 100644 index 0000000000..396058457b --- /dev/null +++ b/apps/hermes/client/rust/src/apis/rest_api.rs @@ -0,0 +1,862 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use super::{configuration, ContentType, Error}; +use crate::{apis::ResponseContent, models}; +use reqwest; +use serde::{de::Error as _, Deserialize, Serialize}; + +/// struct for typed errors of method [`get_price_feed`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetPriceFeedError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_vaa`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetVaaError { + Status404(String), + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_vaa_ccip`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetVaaCcipError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`latest_price_feeds`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum LatestPriceFeedsError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`latest_price_updates`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum LatestPriceUpdatesError { + Status404(String), + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`latest_publisher_stake_caps`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum LatestPublisherStakeCapsError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`latest_twaps`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum LatestTwapsError { + Status404(String), + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`latest_vaas`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum LatestVaasError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`price_feed_ids`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PriceFeedIdsError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`price_feeds_metadata`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PriceFeedsMetadataError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`price_stream_sse_handler`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PriceStreamSseHandlerError { + Status404(String), + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`timestamp_price_updates`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum TimestampPriceUpdatesError { + Status404(String), + UnknownValue(serde_json::Value), +} + +/// **Deprecated: use /v2/updates/price/{publish_time} instead** Get a price update for a price feed with a specific timestamp Given a price feed id and timestamp, retrieve the Pyth price update closest to that timestamp. +pub async fn get_price_feed( + configuration: &configuration::Configuration, + id: &str, + publish_time: i64, + verbose: Option, + binary: Option, +) -> Result> { + // add a prefix to parameters to efficiently prevent name collisions + let p_id = id; + let p_publish_time = publish_time; + let p_verbose = verbose; + let p_binary = binary; + + let uri_str = format!("{}/api/get_price_feed", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = req_builder.query(&[("id", &p_id.to_string())]); + req_builder = req_builder.query(&[("publish_time", &p_publish_time.to_string())]); + if let Some(ref param_value) = p_verbose { + req_builder = req_builder.query(&[("verbose", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_binary { + req_builder = req_builder.query(&[("binary", ¶m_value.to_string())]); + } + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RpcPriceFeed`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RpcPriceFeed`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// **Deprecated: use /v2/updates/price/{publish_time} instead** Get a VAA for a price feed with a specific timestamp Given a price feed id and timestamp, retrieve the Pyth price update closest to that timestamp. +pub async fn get_vaa( + configuration: &configuration::Configuration, + id: &str, + publish_time: i64, +) -> Result> { + // add a prefix to parameters to efficiently prevent name collisions + let p_id = id; + let p_publish_time = publish_time; + + let uri_str = format!("{}/api/get_vaa", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = req_builder.query(&[("id", &p_id.to_string())]); + req_builder = req_builder.query(&[("publish_time", &p_publish_time.to_string())]); + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetVaaResponse`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetVaaResponse`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// **Deprecated: use /v2/updates/price/{publish_time} instead** Get a VAA for a price feed using CCIP This endpoint accepts a single argument which is a hex-encoded byte string of the following form: ` ` +pub async fn get_vaa_ccip( + configuration: &configuration::Configuration, + data: std::path::PathBuf, +) -> Result> { + // add a prefix to parameters to efficiently prevent name collisions + let p_data = data; + + let uri_str = format!("{}/api/get_vaa_ccip", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = req_builder.query(&[("data", &p_data.display().to_string())]); + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetVaaCcipResponse`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetVaaCcipResponse`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// **Deprecated: use /v2/updates/price/latest instead** 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. +pub async fn latest_price_feeds( + configuration: &configuration::Configuration, + ids: Vec, + verbose: Option, + binary: Option, +) -> Result, Error> { + // add a prefix to parameters to efficiently prevent name collisions + let p_ids = ids; + let p_verbose = verbose; + let p_binary = binary; + + let uri_str = format!("{}/api/latest_price_feeds", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = match "multi" { + "multi" => req_builder.query( + &p_ids + .into_iter() + .map(|p| ("ids[]".to_owned(), p.to_string())) + .collect::>(), + ), + _ => req_builder.query(&[( + "ids[]", + &p_ids + .into_iter() + .map(|p| p.to_string()) + .collect::>() + .join(",") + .to_string(), + )]), + }; + if let Some(ref param_value) = p_verbose { + req_builder = req_builder.query(&[("verbose", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_binary { + req_builder = req_builder.query(&[("binary", ¶m_value.to_string())]); + } + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `Vec<models::RpcPriceFeed>`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `Vec<models::RpcPriceFeed>`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// 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. +pub async fn latest_price_updates( + configuration: &configuration::Configuration, + ids: Vec, + encoding: Option, + parsed: Option, + ignore_invalid_price_ids: Option, +) -> Result> { + // add a prefix to parameters to efficiently prevent name collisions + let p_ids = ids; + let p_encoding = encoding; + let p_parsed = parsed; + let p_ignore_invalid_price_ids = ignore_invalid_price_ids; + + let uri_str = format!("{}/v2/updates/price/latest", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = match "multi" { + "multi" => req_builder.query( + &p_ids + .into_iter() + .map(|p| ("ids[]".to_owned(), p.to_string())) + .collect::>(), + ), + _ => req_builder.query(&[( + "ids[]", + &p_ids + .into_iter() + .map(|p| p.to_string()) + .collect::>() + .join(",") + .to_string(), + )]), + }; + if let Some(ref param_value) = p_encoding { + req_builder = req_builder.query(&[("encoding", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_parsed { + req_builder = req_builder.query(&[("parsed", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_ignore_invalid_price_ids { + req_builder = req_builder.query(&[("ignore_invalid_price_ids", ¶m_value.to_string())]); + } + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::PriceUpdate`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::PriceUpdate`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// Get the most recent publisher stake caps update data. +pub async fn latest_publisher_stake_caps( + configuration: &configuration::Configuration, + encoding: Option, + parsed: Option, +) -> Result> +{ + // add a prefix to parameters to efficiently prevent name collisions + let p_encoding = encoding; + let p_parsed = parsed; + + let uri_str = format!( + "{}/v2/updates/publisher_stake_caps/latest", + configuration.base_path + ); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + if let Some(ref param_value) = p_encoding { + req_builder = req_builder.query(&[("encoding", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_parsed { + req_builder = req_builder.query(&[("parsed", ¶m_value.to_string())]); + } + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::LatestPublisherStakeCapsUpdateDataResponse`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::LatestPublisherStakeCapsUpdateDataResponse`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// Get the latest TWAP by price feed id with a custom time window. Given a collection of price feed ids, retrieve the latest Pyth TWAP price for each price feed. +pub async fn latest_twaps( + configuration: &configuration::Configuration, + window_seconds: i64, + ids_left_square_bracket_right_square_bracket: Vec, + encoding: Option, + parsed: Option, + ignore_invalid_price_ids: Option, +) -> Result> { + // add a prefix to parameters to efficiently prevent name collisions + let p_window_seconds = window_seconds; + let p_ids_left_square_bracket_right_square_bracket = + ids_left_square_bracket_right_square_bracket; + let p_encoding = encoding; + let p_parsed = parsed; + let p_ignore_invalid_price_ids = ignore_invalid_price_ids; + + let uri_str = format!( + "{}/v2/updates/twap/{window_seconds}/latest", + configuration.base_path, + window_seconds = p_window_seconds + ); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = match "multi" { + "multi" => req_builder.query( + &p_ids_left_square_bracket_right_square_bracket + .into_iter() + .map(|p| ("ids[]".to_owned(), p.to_string())) + .collect::>(), + ), + _ => req_builder.query(&[( + "ids[]", + &p_ids_left_square_bracket_right_square_bracket + .into_iter() + .map(|p| p.to_string()) + .collect::>() + .join(",") + .to_string(), + )]), + }; + if let Some(ref param_value) = p_encoding { + req_builder = req_builder.query(&[("encoding", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_parsed { + req_builder = req_builder.query(&[("parsed", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_ignore_invalid_price_ids { + req_builder = req_builder.query(&[("ignore_invalid_price_ids", ¶m_value.to_string())]); + } + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::TwapsResponse`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::TwapsResponse`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// **Deprecated: use /v2/updates/price/latest instead** Get VAAs for a set of price feed ids. Given a collection of price feed ids, retrieve the latest VAA for each. The returned VAA(s) can be submitted to the Pyth contract to update the on-chain price. If VAAs are not found for every provided price ID the call will fail. +pub async fn latest_vaas( + configuration: &configuration::Configuration, + ids_left_square_bracket_right_square_bracket: Vec, +) -> Result, Error> { + // add a prefix to parameters to efficiently prevent name collisions + let p_ids_left_square_bracket_right_square_bracket = + ids_left_square_bracket_right_square_bracket; + + let uri_str = format!("{}/api/latest_vaas", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = match "multi" { + "multi" => req_builder.query( + &p_ids_left_square_bracket_right_square_bracket + .into_iter() + .map(|p| ("ids[]".to_owned(), p.to_string())) + .collect::>(), + ), + _ => req_builder.query(&[( + "ids[]", + &p_ids_left_square_bracket_right_square_bracket + .into_iter() + .map(|p| p.to_string()) + .collect::>() + .join(",") + .to_string(), + )]), + }; + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `Vec<String>`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `Vec<String>`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// **Deprecated: use /v2/price_feeds instead** Get the set of price feed IDs. This endpoint fetches all of the price feed IDs for which price updates can be retrieved. +pub async fn price_feed_ids( + configuration: &configuration::Configuration, +) -> Result, Error> { + let uri_str = format!("{}/api/price_feed_ids", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `Vec<String>`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `Vec<String>`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// Get the set of price feeds. This endpoint fetches all price feeds from the Pyth network. It can be filtered by asset type and query string. +pub async fn price_feeds_metadata( + configuration: &configuration::Configuration, + query: Option<&str>, + asset_type: Option, +) -> Result, Error> { + // add a prefix to parameters to efficiently prevent name collisions + let p_query = query; + let p_asset_type = asset_type; + + let uri_str = format!("{}/v2/price_feeds", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + if let Some(ref param_value) = p_query { + req_builder = req_builder.query(&[("query", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_asset_type { + req_builder = req_builder.query(&[("asset_type", ¶m_value.to_string())]); + } + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `Vec<models::PriceFeedMetadata>`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `Vec<models::PriceFeedMetadata>`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// SSE route handler for streaming price updates. The connection will automatically close after 24 hours to prevent resource leaks. Clients should implement reconnection logic to maintain continuous price updates. +pub async fn price_stream_sse_handler( + configuration: &configuration::Configuration, + ids: Vec, + encoding: Option, + parsed: Option, + allow_unordered: Option, + benchmarks_only: Option, + ignore_invalid_price_ids: Option, +) -> Result> { + // add a prefix to parameters to efficiently prevent name collisions + let p_ids = ids; + let p_encoding = encoding; + let p_parsed = parsed; + let p_allow_unordered = allow_unordered; + let p_benchmarks_only = benchmarks_only; + let p_ignore_invalid_price_ids = ignore_invalid_price_ids; + + let uri_str = format!("{}/v2/updates/price/stream", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = match "multi" { + "multi" => req_builder.query( + &p_ids + .into_iter() + .map(|p| ("ids[]".to_owned(), p.to_string())) + .collect::>(), + ), + _ => req_builder.query(&[( + "ids[]", + &p_ids + .into_iter() + .map(|p| p.to_string()) + .collect::>() + .join(",") + .to_string(), + )]), + }; + if let Some(ref param_value) = p_encoding { + req_builder = req_builder.query(&[("encoding", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_parsed { + req_builder = req_builder.query(&[("parsed", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_allow_unordered { + req_builder = req_builder.query(&[("allow_unordered", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_benchmarks_only { + req_builder = req_builder.query(&[("benchmarks_only", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_ignore_invalid_price_ids { + req_builder = req_builder.query(&[("ignore_invalid_price_ids", ¶m_value.to_string())]); + } + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::PriceUpdate`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::PriceUpdate`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} + +/// 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. +pub async fn timestamp_price_updates( + configuration: &configuration::Configuration, + publish_time: i64, + ids: Vec, + encoding: Option, + parsed: Option, + ignore_invalid_price_ids: Option, +) -> Result> { + // add a prefix to parameters to efficiently prevent name collisions + let p_publish_time = publish_time; + let p_ids = ids; + let p_encoding = encoding; + let p_parsed = parsed; + let p_ignore_invalid_price_ids = ignore_invalid_price_ids; + + let uri_str = format!( + "{}/v2/updates/price/{publish_time}", + configuration.base_path, + publish_time = p_publish_time + ); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); + + req_builder = match "multi" { + "multi" => req_builder.query( + &p_ids + .into_iter() + .map(|p| ("ids[]".to_owned(), p.to_string())) + .collect::>(), + ), + _ => req_builder.query(&[( + "ids[]", + &p_ids + .into_iter() + .map(|p| p.to_string()) + .collect::>() + .join(",") + .to_string(), + )]), + }; + if let Some(ref param_value) = p_encoding { + req_builder = req_builder.query(&[("encoding", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_parsed { + req_builder = req_builder.query(&[("parsed", ¶m_value.to_string())]); + } + if let Some(ref param_value) = p_ignore_invalid_price_ids { + req_builder = req_builder.query(&[("ignore_invalid_price_ids", ¶m_value.to_string())]); + } + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + let content_type = resp + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("application/octet-stream"); + let content_type = super::ContentType::from(content_type); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + match content_type { + ContentType::Json => serde_json::from_str(&content).map_err(Error::from), + ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::PriceUpdate`"))), + ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::PriceUpdate`")))), + } + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + status, + content, + entity, + })) + } +} diff --git a/apps/hermes/client/rust/src/lib.rs b/apps/hermes/client/rust/src/lib.rs new file mode 100644 index 0000000000..820a07bccc --- /dev/null +++ b/apps/hermes/client/rust/src/lib.rs @@ -0,0 +1,15 @@ +#![allow(unused_imports)] +#![allow(clippy::too_many_arguments)] + +extern crate reqwest; +extern crate serde; +extern crate serde_json; +extern crate serde_repr; +extern crate url; + +pub mod apis; +pub mod models; +pub mod streaming; + +pub use crate::apis::configuration::Configuration; +pub use crate::streaming::create_price_update_stream; diff --git a/apps/hermes/client/rust/src/models/asset_type.rs b/apps/hermes/client/rust/src/models/asset_type.rs new file mode 100644 index 0000000000..16d0a33540 --- /dev/null +++ b/apps/hermes/client/rust/src/models/asset_type.rs @@ -0,0 +1,47 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum AssetType { + #[serde(rename = "crypto")] + Crypto, + #[serde(rename = "fx")] + Fx, + #[serde(rename = "equity")] + Equity, + #[serde(rename = "metal")] + Metal, + #[serde(rename = "rates")] + Rates, + #[serde(rename = "crypto_redemption_rate")] + CryptoRedemptionRate, +} + +impl std::fmt::Display for AssetType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Crypto => write!(f, "crypto"), + Self::Fx => write!(f, "fx"), + Self::Equity => write!(f, "equity"), + Self::Metal => write!(f, "metal"), + Self::Rates => write!(f, "rates"), + Self::CryptoRedemptionRate => write!(f, "crypto_redemption_rate"), + } + } +} + +impl Default for AssetType { + fn default() -> AssetType { + Self::Crypto + } +} diff --git a/apps/hermes/client/rust/src/models/binary_update.rs b/apps/hermes/client/rust/src/models/binary_update.rs new file mode 100644 index 0000000000..6d51a343f2 --- /dev/null +++ b/apps/hermes/client/rust/src/models/binary_update.rs @@ -0,0 +1,26 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct BinaryUpdate { + #[serde(rename = "data")] + pub data: Vec, + #[serde(rename = "encoding")] + pub encoding: models::EncodingType, +} + +impl BinaryUpdate { + pub fn new(data: Vec, encoding: models::EncodingType) -> BinaryUpdate { + BinaryUpdate { data, encoding } + } +} diff --git a/apps/hermes/client/rust/src/models/encoding_type.rs b/apps/hermes/client/rust/src/models/encoding_type.rs new file mode 100644 index 0000000000..e91b27cb52 --- /dev/null +++ b/apps/hermes/client/rust/src/models/encoding_type.rs @@ -0,0 +1,35 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum EncodingType { + #[serde(rename = "hex")] + Hex, + #[serde(rename = "base64")] + Base64, +} + +impl std::fmt::Display for EncodingType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Hex => write!(f, "hex"), + Self::Base64 => write!(f, "base64"), + } + } +} + +impl Default for EncodingType { + fn default() -> EncodingType { + Self::Hex + } +} diff --git a/apps/hermes/client/rust/src/models/get_vaa_ccip_response.rs b/apps/hermes/client/rust/src/models/get_vaa_ccip_response.rs new file mode 100644 index 0000000000..e1b147fd2c --- /dev/null +++ b/apps/hermes/client/rust/src/models/get_vaa_ccip_response.rs @@ -0,0 +1,24 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct GetVaaCcipResponse { + #[serde(rename = "data")] + pub data: String, +} + +impl GetVaaCcipResponse { + pub fn new(data: String) -> GetVaaCcipResponse { + GetVaaCcipResponse { data } + } +} diff --git a/apps/hermes/client/rust/src/models/get_vaa_response.rs b/apps/hermes/client/rust/src/models/get_vaa_response.rs new file mode 100644 index 0000000000..d15ecf93bb --- /dev/null +++ b/apps/hermes/client/rust/src/models/get_vaa_response.rs @@ -0,0 +1,27 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct GetVaaResponse { + #[serde(rename = "publishTime")] + pub publish_time: i64, + /// The VAA binary represented as a base64 string. + #[serde(rename = "vaa")] + pub vaa: String, +} + +impl GetVaaResponse { + pub fn new(publish_time: i64, vaa: String) -> GetVaaResponse { + GetVaaResponse { publish_time, vaa } + } +} diff --git a/apps/hermes/client/rust/src/models/latest_publisher_stake_caps_update_data_response.rs b/apps/hermes/client/rust/src/models/latest_publisher_stake_caps_update_data_response.rs new file mode 100644 index 0000000000..b04d0234d1 --- /dev/null +++ b/apps/hermes/client/rust/src/models/latest_publisher_stake_caps_update_data_response.rs @@ -0,0 +1,34 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct LatestPublisherStakeCapsUpdateDataResponse { + #[serde(rename = "binary")] + pub binary: Box, + #[serde( + rename = "parsed", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub parsed: Option>>, +} + +impl LatestPublisherStakeCapsUpdateDataResponse { + pub fn new(binary: models::BinaryUpdate) -> LatestPublisherStakeCapsUpdateDataResponse { + LatestPublisherStakeCapsUpdateDataResponse { + binary: Box::new(binary), + parsed: None, + } + } +} diff --git a/apps/hermes/client/rust/src/models/mod.rs b/apps/hermes/client/rust/src/models/mod.rs new file mode 100644 index 0000000000..2522248a67 --- /dev/null +++ b/apps/hermes/client/rust/src/models/mod.rs @@ -0,0 +1,36 @@ +pub mod asset_type; +pub use self::asset_type::AssetType; +pub mod binary_update; +pub use self::binary_update::BinaryUpdate; +pub mod encoding_type; +pub use self::encoding_type::EncodingType; +pub mod get_vaa_ccip_response; +pub use self::get_vaa_ccip_response::GetVaaCcipResponse; +pub mod get_vaa_response; +pub use self::get_vaa_response::GetVaaResponse; +pub mod latest_publisher_stake_caps_update_data_response; +pub use self::latest_publisher_stake_caps_update_data_response::LatestPublisherStakeCapsUpdateDataResponse; +pub mod parsed_price_feed_twap; +pub use self::parsed_price_feed_twap::ParsedPriceFeedTwap; +pub mod parsed_price_update; +pub use self::parsed_price_update::ParsedPriceUpdate; +pub mod parsed_publisher_stake_cap; +pub use self::parsed_publisher_stake_cap::ParsedPublisherStakeCap; +pub mod parsed_publisher_stake_caps_update; +pub use self::parsed_publisher_stake_caps_update::ParsedPublisherStakeCapsUpdate; +pub mod price_feed_metadata; +pub use self::price_feed_metadata::PriceFeedMetadata; +pub mod price_update; +pub use self::price_update::PriceUpdate; +pub mod rpc_price; +pub use self::rpc_price::RpcPrice; +pub mod rpc_price_feed; +pub use self::rpc_price_feed::RpcPriceFeed; +pub mod rpc_price_feed_metadata; +pub use self::rpc_price_feed_metadata::RpcPriceFeedMetadata; +pub mod rpc_price_feed_metadata_v2; +pub use self::rpc_price_feed_metadata_v2::RpcPriceFeedMetadataV2; +pub mod sse_event; +pub use self::sse_event::SseEvent; +pub mod twaps_response; +pub use self::twaps_response::TwapsResponse; diff --git a/apps/hermes/client/rust/src/models/parsed_price_feed_twap.rs b/apps/hermes/client/rust/src/models/parsed_price_feed_twap.rs new file mode 100644 index 0000000000..daa946bb69 --- /dev/null +++ b/apps/hermes/client/rust/src/models/parsed_price_feed_twap.rs @@ -0,0 +1,47 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct ParsedPriceFeedTwap { + /// The % of slots where the network was down over the TWAP window. A value of zero indicates no slots were missed over the window, and a value of one indicates that every slot was missed over the window. This is a float value stored as a string to avoid precision loss. + #[serde(rename = "down_slots_ratio")] + pub down_slots_ratio: String, + /// The end unix timestamp of the window + #[serde(rename = "end_timestamp")] + pub end_timestamp: i64, + #[serde(rename = "id")] + pub id: String, + /// The start unix timestamp of the window + #[serde(rename = "start_timestamp")] + pub start_timestamp: i64, + #[serde(rename = "twap")] + pub twap: Box, +} + +impl ParsedPriceFeedTwap { + pub fn new( + down_slots_ratio: String, + end_timestamp: i64, + id: String, + start_timestamp: i64, + twap: models::RpcPrice, + ) -> ParsedPriceFeedTwap { + ParsedPriceFeedTwap { + down_slots_ratio, + end_timestamp, + id, + start_timestamp, + twap: Box::new(twap), + } + } +} diff --git a/apps/hermes/client/rust/src/models/parsed_price_update.rs b/apps/hermes/client/rust/src/models/parsed_price_update.rs new file mode 100644 index 0000000000..b503de7d69 --- /dev/null +++ b/apps/hermes/client/rust/src/models/parsed_price_update.rs @@ -0,0 +1,40 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct ParsedPriceUpdate { + #[serde(rename = "ema_price")] + pub ema_price: Box, + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "metadata")] + pub metadata: Box, + #[serde(rename = "price")] + pub price: Box, +} + +impl ParsedPriceUpdate { + pub fn new( + ema_price: models::RpcPrice, + id: String, + metadata: models::RpcPriceFeedMetadataV2, + price: models::RpcPrice, + ) -> ParsedPriceUpdate { + ParsedPriceUpdate { + ema_price: Box::new(ema_price), + id, + metadata: Box::new(metadata), + price: Box::new(price), + } + } +} diff --git a/apps/hermes/client/rust/src/models/parsed_publisher_stake_cap.rs b/apps/hermes/client/rust/src/models/parsed_publisher_stake_cap.rs new file mode 100644 index 0000000000..46e6cbf7e7 --- /dev/null +++ b/apps/hermes/client/rust/src/models/parsed_publisher_stake_cap.rs @@ -0,0 +1,26 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct ParsedPublisherStakeCap { + #[serde(rename = "cap")] + pub cap: i64, + #[serde(rename = "publisher")] + pub publisher: String, +} + +impl ParsedPublisherStakeCap { + pub fn new(cap: i64, publisher: String) -> ParsedPublisherStakeCap { + ParsedPublisherStakeCap { cap, publisher } + } +} diff --git a/apps/hermes/client/rust/src/models/parsed_publisher_stake_caps_update.rs b/apps/hermes/client/rust/src/models/parsed_publisher_stake_caps_update.rs new file mode 100644 index 0000000000..5d91f640e9 --- /dev/null +++ b/apps/hermes/client/rust/src/models/parsed_publisher_stake_caps_update.rs @@ -0,0 +1,28 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct ParsedPublisherStakeCapsUpdate { + #[serde(rename = "publisher_stake_caps")] + pub publisher_stake_caps: Vec, +} + +impl ParsedPublisherStakeCapsUpdate { + pub fn new( + publisher_stake_caps: Vec, + ) -> ParsedPublisherStakeCapsUpdate { + ParsedPublisherStakeCapsUpdate { + publisher_stake_caps, + } + } +} diff --git a/apps/hermes/client/rust/src/models/price_feed_metadata.rs b/apps/hermes/client/rust/src/models/price_feed_metadata.rs new file mode 100644 index 0000000000..42a1f55f11 --- /dev/null +++ b/apps/hermes/client/rust/src/models/price_feed_metadata.rs @@ -0,0 +1,29 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct PriceFeedMetadata { + #[serde(rename = "attributes")] + pub attributes: std::collections::HashMap, + #[serde(rename = "id")] + pub id: String, +} + +impl PriceFeedMetadata { + pub fn new( + attributes: std::collections::HashMap, + id: String, + ) -> PriceFeedMetadata { + PriceFeedMetadata { attributes, id } + } +} diff --git a/apps/hermes/client/rust/src/models/price_update.rs b/apps/hermes/client/rust/src/models/price_update.rs new file mode 100644 index 0000000000..47058a5f0a --- /dev/null +++ b/apps/hermes/client/rust/src/models/price_update.rs @@ -0,0 +1,34 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct PriceUpdate { + #[serde(rename = "binary")] + pub binary: Box, + #[serde( + rename = "parsed", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub parsed: Option>>, +} + +impl PriceUpdate { + pub fn new(binary: models::BinaryUpdate) -> PriceUpdate { + PriceUpdate { + binary: Box::new(binary), + parsed: None, + } + } +} diff --git a/apps/hermes/client/rust/src/models/rpc_price.rs b/apps/hermes/client/rust/src/models/rpc_price.rs new file mode 100644 index 0000000000..cd37b85210 --- /dev/null +++ b/apps/hermes/client/rust/src/models/rpc_price.rs @@ -0,0 +1,41 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +/// RpcPrice : A price with a degree of uncertainty at a certain time, represented as a price +- a confidence interval. The confidence interval roughly corresponds to the standard error of a normal distribution. Both the price and confidence are stored in a fixed-point numeric representation, `x * 10^expo`, where `expo` is the exponent. For example: +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RpcPrice { + /// The confidence interval associated with the price, stored as a string to avoid precision loss + #[serde(rename = "conf")] + pub conf: String, + /// The exponent associated with both the price and confidence interval. Multiply those values by `10^expo` to get the real value. + #[serde(rename = "expo")] + pub expo: i32, + /// The price itself, stored as a string to avoid precision loss + #[serde(rename = "price")] + pub price: String, + /// When the price was published. The `publish_time` is a unix timestamp, i.e., the number of seconds since the Unix epoch (00:00:00 UTC on 1 Jan 1970). + #[serde(rename = "publish_time")] + pub publish_time: i64, +} + +impl RpcPrice { + /// A price with a degree of uncertainty at a certain time, represented as a price +- a confidence interval. The confidence interval roughly corresponds to the standard error of a normal distribution. Both the price and confidence are stored in a fixed-point numeric representation, `x * 10^expo`, where `expo` is the exponent. For example: + pub fn new(conf: String, expo: i32, price: String, publish_time: i64) -> RpcPrice { + RpcPrice { + conf, + expo, + price, + publish_time, + } + } +} diff --git a/apps/hermes/client/rust/src/models/rpc_price_feed.rs b/apps/hermes/client/rust/src/models/rpc_price_feed.rs new file mode 100644 index 0000000000..ecba7300f3 --- /dev/null +++ b/apps/hermes/client/rust/src/models/rpc_price_feed.rs @@ -0,0 +1,49 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RpcPriceFeed { + #[serde(rename = "ema_price")] + pub ema_price: Box, + #[serde(rename = "id")] + pub id: String, + #[serde( + rename = "metadata", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub metadata: Option>>, + #[serde(rename = "price")] + pub price: Box, + /// The VAA binary represented as a base64 string. + #[serde( + rename = "vaa", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub vaa: Option>, +} + +impl RpcPriceFeed { + pub fn new(ema_price: models::RpcPrice, id: String, price: models::RpcPrice) -> RpcPriceFeed { + RpcPriceFeed { + ema_price: Box::new(ema_price), + id, + metadata: None, + price: Box::new(price), + vaa: None, + } + } +} diff --git a/apps/hermes/client/rust/src/models/rpc_price_feed_metadata.rs b/apps/hermes/client/rust/src/models/rpc_price_feed_metadata.rs new file mode 100644 index 0000000000..d24151e475 --- /dev/null +++ b/apps/hermes/client/rust/src/models/rpc_price_feed_metadata.rs @@ -0,0 +1,50 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RpcPriceFeedMetadata { + #[serde(rename = "emitter_chain")] + pub emitter_chain: i32, + #[serde( + rename = "prev_publish_time", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub prev_publish_time: Option>, + #[serde( + rename = "price_service_receive_time", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub price_service_receive_time: Option>, + #[serde( + rename = "slot", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub slot: Option>, +} + +impl RpcPriceFeedMetadata { + pub fn new(emitter_chain: i32) -> RpcPriceFeedMetadata { + RpcPriceFeedMetadata { + emitter_chain, + prev_publish_time: None, + price_service_receive_time: None, + slot: None, + } + } +} diff --git a/apps/hermes/client/rust/src/models/rpc_price_feed_metadata_v2.rs b/apps/hermes/client/rust/src/models/rpc_price_feed_metadata_v2.rs new file mode 100644 index 0000000000..5376da7057 --- /dev/null +++ b/apps/hermes/client/rust/src/models/rpc_price_feed_metadata_v2.rs @@ -0,0 +1,47 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RpcPriceFeedMetadataV2 { + #[serde( + rename = "prev_publish_time", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub prev_publish_time: Option>, + #[serde( + rename = "proof_available_time", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub proof_available_time: Option>, + #[serde( + rename = "slot", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub slot: Option>, +} + +impl RpcPriceFeedMetadataV2 { + pub fn new() -> RpcPriceFeedMetadataV2 { + RpcPriceFeedMetadataV2 { + prev_publish_time: None, + proof_available_time: None, + slot: None, + } + } +} diff --git a/apps/hermes/client/rust/src/models/sse_event.rs b/apps/hermes/client/rust/src/models/sse_event.rs new file mode 100644 index 0000000000..779bd480c4 --- /dev/null +++ b/apps/hermes/client/rust/src/models/sse_event.rs @@ -0,0 +1,43 @@ +use super::parsed_price_update::ParsedPriceUpdate; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BinaryData { + #[serde(rename = "encoding")] + pub encoding: String, + + #[serde(rename = "data")] + pub data: Vec, + + #[serde(flatten)] + pub additional_properties: HashMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SseEvent { + #[serde(rename = "binary", skip_serializing_if = "Option::is_none")] + pub binary: Option, + + #[serde(rename = "parsed", skip_serializing_if = "Option::is_none")] + pub parsed: Option>, + + #[serde(flatten)] + pub additional_properties: HashMap, +} + +impl SseEvent { + pub fn new() -> SseEvent { + SseEvent { + binary: None, + parsed: None, + additional_properties: HashMap::new(), + } + } +} + +impl Default for SseEvent { + fn default() -> Self { + Self::new() + } +} diff --git a/apps/hermes/client/rust/src/models/twaps_response.rs b/apps/hermes/client/rust/src/models/twaps_response.rs new file mode 100644 index 0000000000..79ebc0f353 --- /dev/null +++ b/apps/hermes/client/rust/src/models/twaps_response.rs @@ -0,0 +1,35 @@ +/* + * hermes + * + * Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle. + * + * The version of the OpenAPI document: 0.8.6 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct TwapsResponse { + #[serde(rename = "binary")] + pub binary: Box, + /// The calculated TWAPs for each price ID + #[serde( + rename = "parsed", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub parsed: Option>>, +} + +impl TwapsResponse { + pub fn new(binary: models::BinaryUpdate) -> TwapsResponse { + TwapsResponse { + binary: Box::new(binary), + parsed: None, + } + } +} diff --git a/apps/hermes/client/rust/src/streaming.rs b/apps/hermes/client/rust/src/streaming.rs new file mode 100644 index 0000000000..e5898638ff --- /dev/null +++ b/apps/hermes/client/rust/src/streaming.rs @@ -0,0 +1,98 @@ +use crate::apis::configuration::Configuration; +use crate::models::{EncodingType, ParsedPriceUpdate, PriceUpdate}; +use futures_util::stream::{Stream, StreamExt}; +use std::error::Error; + +pub async fn create_price_update_stream( + config: &Configuration, + price_feed_ids: Vec, + encoding: Option, + allow_unordered: Option, + benchmarks_only: Option, + ignore_invalid_price_ids: Option, +) -> Result< + impl Stream>>, + Box, +> { + let base_url = format!("{}/v2/updates/price/stream", config.base_path); + let mut url = reqwest::Url::parse(&base_url)?; + + let mut query_pairs = url.query_pairs_mut(); + for id in &price_feed_ids { + query_pairs.append_pair("ids[]", id); + } + + if let Some(enc) = encoding { + query_pairs.append_pair("encoding", &enc.to_string()); + } else { + query_pairs.append_pair("encoding", "base64"); + } + + query_pairs.append_pair("parsed", "true"); + + if let Some(allow) = allow_unordered { + query_pairs.append_pair("allow_unordered", &allow.to_string()); + } + + if let Some(benchmarks) = benchmarks_only { + query_pairs.append_pair("benchmarks_only", &benchmarks.to_string()); + } + + if let Some(ignore) = ignore_invalid_price_ids { + query_pairs.append_pair("ignore_invalid_price_ids", &ignore.to_string()); + } + + drop(query_pairs); + + let client = reqwest::Client::builder().build()?; + + let response = client + .get(url) + .header("Accept", "text/event-stream") + .send() + .await?; + + if !response.status().is_success() { + return Err(format!("Failed to connect to SSE endpoint: {}", response.status()).into()); + } + + let stream = response.bytes_stream(); + + let sse_stream = eventsource_stream::EventStream::new(stream) + .map(move |event_result| match event_result { + Ok(event) => { + if event.event != "message" { + return Err(format!("Unexpected event type: {}", event.event).into()); + } + + let data = &event.data; + + println!("Received SSE data: {}", data); + + match serde_json::from_str::(data) { + Ok(sse_event) => { + if let Some(parsed_updates) = sse_event.parsed { + let stream = + parsed_updates + .into_iter() + .map(Ok) + .collect::>, + >>(); + Ok(futures_util::stream::iter(stream)) + } else { + Err("No parsed price updates in the response".into()) + } + } + Err(e) => Err(format!("Failed to parse price update: {}", e).into()), + } + } + Err(e) => Err(format!("Error in SSE stream: {}", e).into()), + }) + .flat_map(|result| match result { + Ok(stream) => stream, + Err(e) => futures_util::stream::iter(vec![Err(e)]), + }); + + Ok(sse_stream) +}