Skip to content
This repository was archived by the owner on Jun 1, 2026. It is now read-only.

Perps accounts stats - #889

Merged
gemdev111 merged 11 commits into
mainfrom
perps_portfolio
Jan 22, 2026
Merged

gemdev111 merged 11 commits into
mainfrom
perps_portfolio

Conversation

@gemdev111

Copy link
Copy Markdown
Contributor

No description provided.

@semanticdiff-com

semanticdiff-com Bot commented Jan 15, 2026 •

Copy link
Copy Markdown

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @gemdev111, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's capability to handle and display perpetual portfolio data. It establishes a robust foundation by defining new data models, extending existing traits to support portfolio retrieval, and implementing the necessary logic within the Hypercore client to interact with its portfolio API. The changes also ensure that this new functionality is properly exposed through the gateway and made available for foreign function interface consumption, providing a comprehensive solution for portfolio tracking.

Highlights

  • New Portfolio Data Structures: Introduced core Portfolio, PortfolioDataPoint, and PortfolioTimeframeData structs in the primitives crate, designed for representing detailed portfolio performance across various timeframes (day, week, month, all-time, and perpetual equivalents).
  • Chain Trait Extension: The ChainPerpetual trait in chain_traits has been extended with a new get_portfolio asynchronous method, providing a standardized interface for fetching portfolio data from different chain implementations.
  • Hypercore Client Integration: The Hypercore client (gem_hypercore) now includes specific data models and parsing logic for Hypercore's portfolio API responses. It implements the get_portfolio trait method, enabling it to fetch and process portfolio data from the Hypercore backend, complete with a new integration test.
  • Gateway and FFI Exposure: The GemGateway now exposes a get_portfolio method, making this new functionality accessible at a higher level. Additionally, FFI-compatible types for portfolio data have been defined in gemstone, allowing seamless integration with client applications (e.g., Swift).

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request introduces portfolio functionality across chain_traits, primitives, gem_hypercore, and gemstone crates. It defines new data structures for portfolio data, implements a get_portfolio method in the ChainPerpetual trait, and provides an implementation for the Hypercore client. Overall, the changes are well-structured, but there are a few areas that could be improved for robustness and correctness, particularly regarding data type handling and a critical recursive call.

}

async fn get_portfolio(&self, address: String) -> Result<Portfolio, Box<dyn Error + Sync + Send>> {
self.get_portfolio(&address).await

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This line appears to be a recursive call to self.get_portfolio(&address).await. Since self here refers to HyperCoreClient<C>, and this method is implementing the ChainPerpetual trait for HyperCoreClient<C>, calling self.get_portfolio again will call this very method, leading to infinite recursion and a stack overflow. You should be calling the get_portfolio method on the underlying RPC client, likely self.client.get_portfolio(&address).await or similar, depending on how the RPC client is exposed.

Suggested change
self.get_portfolio(&address).await
self.client.get_portfolio(&address).await

Comment on lines +8 to +10
pub account_value_history: Vec<(i64, String)>,
pub pnl_history: Vec<(i64, String)>,
pub vlm: String,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Storing numerical values like account_value_history, pnl_history, and vlm as String can lead to runtime parsing errors and performance overhead if these values are frequently converted to numeric types for calculations. It's generally more robust to store them as appropriate numeric types (e.g., f64, Decimal if precision is critical) directly.

}

fn timestamp_to_datetime(timestamp_ms: i64) -> DateTime<Utc> {
Utc.timestamp_millis_opt(timestamp_ms).single().unwrap_or_else(Utc::now)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The unwrap_or_else(Utc::now) call for timestamp_millis_opt can mask issues with invalid timestamps by silently replacing them with the current time. It would be more robust to propagate this potential error (e.g., by returning Option<DateTime<Utc>> or a Result) or explicitly handle it, rather than silently substituting potentially incorrect data.

"perpWeek" => portfolio.perp_week = Some(data.into()),
"perpMonth" => portfolio.perp_month = Some(data.into()),
"perpAllTime" => portfolio.perp_all_time = Some(data.into()),
_ => {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The _ => {} arm in the match statement silently ignores any unknown timeframe values. While this might be the intended behavior for future-proofing, it could also hide issues if an unexpected timeframe is received due to an API change or data corruption. Consider logging a warning for unknown timeframes to aid debugging or returning an error if strict parsing is required.

Comment thread crates/primitives/src/portfolio.rs Outdated
#[serde(rename_all = "camelCase")]
pub struct PortfolioDataPoint {
pub date: DateTime<Utc>,
pub value: String,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the gem_hypercore crate, storing value as a String in PortfolioDataPoint can be problematic. If value represents a numerical quantity that will be used in calculations, it should ideally be stored as a numeric type (e.g., f64 or a fixed-point decimal type) to avoid repeated parsing and potential precision issues.

Comment thread crates/primitives/src/portfolio.rs Outdated
pub struct PortfolioTimeframeData {
pub account_value_history: Vec<PortfolioDataPoint>,
pub pnl_history: Vec<PortfolioDataPoint>,
pub volume: String,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The volume field in PortfolioTimeframeData is also stored as a String. If this represents a numerical volume, consider changing its type to a numeric one for consistency and to prevent parsing errors or inefficiencies during calculations.

Comment thread gemstone/src/models/portfolio.rs Outdated
#[uniffi::remote(Record)]
pub struct GemPortfolioDataPoint {
pub date: DateTime<Utc>,
pub value: String,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The value field in GemPortfolioDataPoint is defined as a String. If this field is intended to hold a numerical value, it would be more appropriate and efficient to use a numeric type (e.g., f64 or GemBigInt/GemBigUint if arbitrary precision is needed) to avoid repeated string parsing and potential runtime errors.

Comment thread gemstone/src/models/portfolio.rs Outdated
pub struct GemPortfolioTimeframeData {
pub account_value_history: Vec<PortfolioDataPoint>,
pub pnl_history: Vec<PortfolioDataPoint>,
pub volume: String,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The volume field in GemPortfolioTimeframeData is also a String. For consistency and better data handling, if volume represents a numerical quantity, it should be changed to a numeric type.

Replaces generic portfolio types with PerpetualPortfolio-specific types across primitives, gem_hypercore, and gemstone. Updates trait and method names to clarify perpetual-specific functionality, adjusts data structures for type safety (e.g., volume as f64), and updates mapping, serialization, and test code accordingly. This improves clarity and correctness for perpetual trading portfolio data handling.
@gemdev111 gemdev111 changed the title Perps portfolio Perps accounts stats Jan 21, 2026
@gemdev111
gemdev111 marked this pull request as ready for review January 22, 2026 17:02
@gemdev111
gemdev111 merged commit a3a3d7c into main Jan 22, 2026
7 checks passed
@gemdev111
gemdev111 deleted the perps_portfolio branch January 22, 2026 17:02
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant