Skip to content

Commit

Permalink
feat: Add Vaults REST API
Browse files Browse the repository at this point in the history
  • Loading branch information
v0-e committed Nov 21, 2024
1 parent 6370149 commit 9ab42e9
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 0 deletions.
1 change: 1 addition & 0 deletions v4-client-rs/client/examples/support/constants.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#[allow(dead_code)]
pub const TEST_MNEMONIC: &str = "mirror actor skill push coach wait confirm orchard lunch mobile athlete gossip awake miracle matter bus reopen team ladder lazy list timber render wait";
43 changes: 43 additions & 0 deletions v4-client-rs/client/examples/vault_endpoint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
mod support;
use anyhow::{Error, Result};
use dydx::config::ClientConfig;
use dydx::indexer::{IndexerClient, PnlTickInterval};

pub struct Rester {
indexer: IndexerClient,
}

impl Rester {
pub async fn connect() -> Result<Self> {
let config = ClientConfig::from_file("client/tests/testnet.toml").await?;
let indexer = IndexerClient::new(config.indexer);
Ok(Self { indexer })
}
}

#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt().try_init().map_err(Error::msg)?;
let rester = Rester::connect().await?;
let indexer = rester.indexer;

// Test values
let resolution = PnlTickInterval::Hour;

let pnls = indexer
.vaults()
.get_megavault_historical_pnl(resolution)
.await?;
tracing::info!("MegaVault historical PnLs: {pnls:?}");

let vaults_pnls = indexer
.vaults()
.get_vaults_historical_pnl(resolution)
.await?;
tracing::info!("Vaults historical PnLs: {vaults_pnls:?}");

let positions = indexer.vaults().get_megavault_positions().await?;
tracing::info!("MegaVault positions: {positions:?}");

Ok(())
}
5 changes: 5 additions & 0 deletions v4-client-rs/client/src/indexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ impl IndexerClient {
self.rest.utility()
}

/// Get vaults query dispatcher.
pub fn vaults(&self) -> rest::Vaults {
self.rest.vaults()
}

/// Get feeds dispatcher.
pub fn feed(&mut self) -> Feeds<'_> {
Feeds::new(&mut self.sock)
Expand Down
7 changes: 7 additions & 0 deletions v4-client-rs/client/src/indexer/rest/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod accounts;
pub mod markets;
pub mod utility;
pub mod vaults;

use super::config::RestConfig;
use super::options::*;
Expand All @@ -10,6 +11,7 @@ use markets::Markets;
use reqwest::Client;
use serde::Serialize;
use utility::Utility;
use vaults::Vaults;

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -55,4 +57,9 @@ impl RestClient {
pub(crate) fn utility(&self) -> Utility<'_> {
Utility::new(self)
}

/// Get vaults query dispatcher.
pub(crate) fn vaults(&self) -> Vaults<'_> {
Vaults::new(self)
}
}
75 changes: 75 additions & 0 deletions v4-client-rs/client/src/indexer/rest/client/vaults.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use super::*;
use anyhow::Error;

/// Vaults dispatcher.
///
/// Check [the example](https://github.com/NethermindEth/dydx-v4-rust/blob/trunk/client/examples/vaults_endpoint.rs).
pub struct Vaults<'a> {
rest: &'a RestClient,
}

impl<'a> Vaults<'a> {
/// Create a new vaults dispatcher.
pub(crate) fn new(rest: &'a RestClient) -> Self {
Self { rest }
}

/// MegaVault historical PnL.
pub async fn get_megavault_historical_pnl(
&self,
resolution: PnlTickInterval,
) -> Result<Vec<PnlTicksResponseObject>, Error> {
let rest = &self.rest;
const URI: &str = "/v4/vault/v1/megavault/historicalPnl";
let url = format!("{}{URI}", rest.config.endpoint);
let resp = rest
.client
.get(url)
.query(&[("resolution", resolution)])
.send()
.await?
.error_for_status()?
.json::<MegaVaultHistoricalPnlResponse>()
.await?
.megavault_pnl;
Ok(resp)
}

/// Vaults historical PnL.
pub async fn get_vaults_historical_pnl(
&self,
resolution: PnlTickInterval,
) -> Result<Vec<VaultHistoricalPnl>, Error> {
let rest = &self.rest;
const URI: &str = "/v4/vault/v1/vaults/historicalPnl";
let url = format!("{}{URI}", rest.config.endpoint);
let resp = rest
.client
.get(url)
.query(&[("resolution", resolution)])
.send()
.await?
.error_for_status()?
.json::<VaultsHistoricalPnLResponse>()
.await?
.vaults_pnl;
Ok(resp)
}

/// MegaVault positions.
pub async fn get_megavault_positions(&self) -> Result<Vec<VaultPosition>, Error> {
let rest = &self.rest;
const URI: &str = "/v4/vault/v1/megavault/positions";
let url = format!("{}{URI}", rest.config.endpoint);
let resp = rest
.client
.get(url)
.send()
.await?
.error_for_status()?
.json::<MegaVaultPositionResponse>()
.await?
.positions;
Ok(resp)
}
}
1 change: 1 addition & 0 deletions v4-client-rs/client/src/indexer/rest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ pub use types::*;
pub use client::accounts::Accounts;
pub use client::markets::Markets;
pub use client::utility::Utility;
pub use client::vaults::Vaults;
60 changes: 60 additions & 0 deletions v4-client-rs/client/src/indexer/rest/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ pub struct ErrorMsg {
#[derive(Deserialize, Debug, Clone, From, Display, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PnlTickId(pub String);

/// PnL tick resolution.
#[derive(
Deserialize, Serialize, Debug, Clone, Copy, From, Display, PartialEq, Eq, PartialOrd, Ord, Hash,
)]
#[serde(rename_all = "lowercase")]
pub enum PnlTickInterval {
/// Hour.
Hour,
/// Day.
Day,
}

/// Transfer id.
#[derive(
Serialize, Deserialize, Debug, Clone, From, Display, PartialEq, Eq, PartialOrd, Ord, Hash,
Expand Down Expand Up @@ -301,3 +313,51 @@ pub struct HistoricalTradingRewardAggregation {
/// Aggregation period.
pub period: TradingRewardAggregationPeriod,
}

/// MegaVault Profit and loss reports.
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct MegaVaultHistoricalPnlResponse {
/// List of PnL reports.
pub megavault_pnl: Vec<PnlTicksResponseObject>,
}

/// MegaVault Profit and loss reports.
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct MegaVaultPositionResponse {
/// List MegaVault positions.
pub positions: Vec<VaultPosition>,
}

/// Vaults profit and loss reports.
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct VaultsHistoricalPnLResponse {
/// List of PnL reports.
pub vaults_pnl: Vec<VaultHistoricalPnl>,
}

/// Vault Profit and loss reports.
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct VaultHistoricalPnl {
/// Associated ticker.
pub ticker: String,
/// List of PnL reports.
pub historical_pnl: Vec<PnlTicksResponseObject>,
}

/// Vault position.
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct VaultPosition {
/// Associated ticker.
pub ticker: String,
/// Asset position.
pub asset_position: Option<AssetPositionResponseObject>,
/// Perpetual position.
pub perpetual_position: Option<PerpetualPositionResponseObject>,
/// Equity.
pub equity: BigDecimal,
}
29 changes: 29 additions & 0 deletions v4-client-rs/client/tests/test_indexer_rest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,35 @@ async fn test_indexer_account_get_rewards_aggregated() -> Result<()> {
Ok(())
}

#[tokio::test]
async fn test_indexer_vaults_get_megavault_historical_pnl() -> Result<()> {
let env = TestEnv::testnet().await?;
let resolution = PnlTickInterval::Hour;
env.indexer
.vaults()
.get_megavault_historical_pnl(resolution)
.await?;
Ok(())
}

#[tokio::test]
async fn test_indexer_vaults_get_vaults_historical_pnl() -> Result<()> {
let env = TestEnv::testnet().await?;
let resolution = PnlTickInterval::Hour;
env.indexer
.vaults()
.get_vaults_historical_pnl(resolution)
.await?;
Ok(())
}

#[tokio::test]
async fn test_indexer_vaults_get_megavault_positions() -> Result<()> {
let env = TestEnv::testnet().await?;
env.indexer.vaults().get_megavault_positions().await?;
Ok(())
}

#[tokio::test]
async fn test_perpetual_market_quantization() -> Result<()> {
let env = TestEnv::testnet().await?;
Expand Down

0 comments on commit 9ab42e9

Please sign in to comment.