Skip to content

Conversation

@dev-pvl
Copy link
Contributor

@dev-pvl dev-pvl commented Nov 26, 2025

Description

Implemented Cardano pool rebalancing and updated APY calculation to reflect the APY of the pool the user is staked in.

Related Issue

Resolve #22794

@dev-pvl dev-pvl requested a review from a team as a code owner November 26, 2025 12:30
@MiroslavProchazka MiroslavProchazka requested a review from a team November 26, 2025 12:32
@MiroslavProchazka
Copy link
Contributor

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@dev-pvl dev-pvl changed the title Feat/cardano pool rebalancing feat(suite): cardano staking pool rebalancing logic Nov 26, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements Cardano pool rebalancing functionality and updates APY calculations to reflect the actual pool a user is staked in, rather than a generic network APY.

Key Changes:

  • Updated APY selectors to accept Account objects instead of just network symbols, enabling pool-specific APY calculations
  • Implemented dynamic Cardano pool selection logic that chooses pools based on saturation levels
  • Added new API integration for fetching Cardano pool statistics from Everstake

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
suite-common/wallet-utils/src/cardanoStakingUtils.ts Added pool rebalancing logic with selectBestCardanoPool and helper functions for pool selection
suite-common/wallet-types/src/cardanoStaking.ts Defined CardanoPoolInfo interface for pool data structure
suite-common/wallet-core/src/stake/stakeTypes.ts Updated endpoint types and added Cardano-specific types for validator stats
suite-common/wallet-core/src/stake/stakeThunks.ts Modified API endpoint configuration and response handling for Cardano pools
suite-common/wallet-core/src/stake/stakeSelectors.ts Updated selectPoolStatsApyData to use account-specific pool data and added pool info selector
suite-common/wallet-constants/src/cardanoConstants.ts Updated backup APY and added saturation threshold constant
packages/suite/src/hooks/wallet/useCardanoStaking.ts Integrated pool selection into staking transaction creation
packages/suite/src/actions/wallet/stake/stakeFormCardanoActions.ts Updated transaction preparation to use dynamic pool selection
Multiple UI components Updated to pass Account objects instead of symbols to APY selectors
Comments suppressed due to low confidence (1)

suite-common/wallet-utils/src/cardanoStakingUtils.ts:1

  • The field is named 'apy' but is populated from 'pool.apr.value'. This naming inconsistency could cause confusion. Either rename the field to 'apr' in CardanoPoolInfo, or ensure the API actually returns APY values.
import { bech32 } from 'bech32';

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Walkthrough

This pull request refactors Cardano staking to use dynamic pool selection instead of hardcoded pool constants. The changes replace symbol-based APY lookups with account object-based lookups across the codebase, introduce new types for pool information (CardanoPoolInfo), update the Everstake API endpoint and response structure, add pool saturation-based selection logic, and thread Cardano pool data through actions, selectors, and components. A new domain (stats.everstake.one) is whitelisted, the Cardano backup APY is adjusted from 4.5 to 2.16, and a pool saturation safe threshold is introduced at 80 percent.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • stakeSelectors.ts: Critical logic refactor for selectPoolStatsApyData — now matches staking pools by ID instead of using symbol; includes fallback logic that warrants verification
  • stakeThunks.ts: API endpoint changes with per-symbol routing and conditional header injection for ADA; response shape now returns pool array instead of simple apy value
  • stakeTypes.ts: New interfaces (EverstakeStakingInfo, CardanoValidatorStats) and endpoint type mapping changes for asset routing
  • cardanoStakingUtils.ts: New pool selection algorithm using saturation thresholds — verify logic for safe/unsafe pool selection
  • stakeFormCardanoActions.ts: Pool parameter threading through transaction preparation — ensure pool data flows correctly through all stake action branches
  • Multiple component files: Repetitive selector argument changes from symbol to account — while consistent, verify no side effects from changed selector input shape

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: introducing Cardano staking pool rebalancing logic, which aligns with the PR's primary objective and file changes.
Description check ✅ Passed The description covers main changes and includes a linked issue reference, but lacks QA notes and detailed technical context as specified in the template.
Linked Issues check ✅ Passed Changes implement pool rebalancing logic through dynamic pool selection, updated APY calculations to use pool data, and new pool saturation thresholds [#22794], meeting the stated coding requirements.
Out of Scope Changes check ✅ Passed All changes relate to Cardano pool rebalancing or supporting APY/pool data infrastructure; the allowedDomains whitelist addition and backup APY constant update are reasonable supporting changes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
suite-common/wallet-utils/src/cardanoStakingUtils.ts (1)

4-8: Cardano pool utilities and rebalancing logic look sound

The new helpers:

  • isCardanoStakedWithEverstake correctly gates on Cardano accounts and matches misc.staking.poolId against the provided CardanoPoolInfo[].
  • selectBestCardanoPool safely filters by CARDANO_POOL_SATURATION_SAFE_THRESHOLD and picks the highest saturation among safe pools, or the lowest saturation overall as a fallback, without risking empty‑array reduce calls.
  • poolBech32ToHex provides the expected bech32→hex conversion used by the pool selector.

To protect this selection logic from future regressions, it would be worth adding a few focused unit tests (e.g., all pools under threshold, all above threshold, empty list) exercising the returned { hex, bech32 } pair.

Also applies to: 35-47, 49-85

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a0b5a4 and 849d975.

📒 Files selected for processing (27)
  • packages/suite-desktop-core/src/config.ts (1 hunks)
  • packages/suite/src/actions/wallet/stake/stakeFormCardanoActions.ts (10 hunks)
  • packages/suite/src/components/suite/StakingProcess/StakingInfo.tsx (1 hunks)
  • packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeInANutshellModal/StakeInANutshellModal.tsx (1 hunks)
  • packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeModal/StakeInfoCards/EstimatedGains.tsx (1 hunks)
  • packages/suite/src/components/wallet/WalletLayout/AccountBanners/StakingBanner.tsx (1 hunks)
  • packages/suite/src/components/wallet/WalletLayout/AccountsMenu/AccountItem/AccountRow/AccountItemContent/AccountItemContent.tsx (2 hunks)
  • packages/suite/src/hooks/wallet/useCardanoStaking.ts (5 hunks)
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboard.tsx (2 hunks)
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardAccountRow.tsx (1 hunks)
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardActivateRow.tsx (1 hunks)
  • packages/suite/src/views/wallet/staking/components/CardanoNewProviderCard.tsx (2 hunks)
  • packages/suite/src/views/wallet/staking/components/CardanoStakingDashboard/NewCardanoStakingDashboard.tsx (2 hunks)
  • packages/suite/src/views/wallet/staking/components/EthStakingDashboard/components/EthStakingDashboard.tsx (1 hunks)
  • packages/suite/src/views/wallet/staking/components/SolStakingDashboard/SolStakingDashboard.tsx (1 hunks)
  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/EmptyStakingCard.tsx (1 hunks)
  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/NewProviderCard.tsx (1 hunks)
  • suite-common/wallet-constants/src/cardanoConstants.ts (2 hunks)
  • suite-common/wallet-core/src/stake/stakeConstants.ts (1 hunks)
  • suite-common/wallet-core/src/stake/stakeReducer.ts (2 hunks)
  • suite-common/wallet-core/src/stake/stakeSelectors.ts (3 hunks)
  • suite-common/wallet-core/src/stake/stakeThunks.ts (3 hunks)
  • suite-common/wallet-core/src/stake/stakeTypes.ts (3 hunks)
  • suite-common/wallet-types/src/cardanoStaking.ts (1 hunks)
  • suite-common/wallet-utils/src/cardanoStakingUtils.ts (2 hunks)
  • suite-native/staking/src/selectors.ts (1 hunks)
  • suite-native/staking/src/solanaStakingSelectors.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts,tsx,jsx}: Use Conventional Commits format for commit messages (e.g., feat(suite):, fix(components):, docs:)
Run yarn build:libs after making dependency changes to rebuild libraries before development
Run yarn lint to lint JavaScript/TypeScript and styles before committing code
Run yarn type-check for TypeScript type checking on all code before submission
Run yarn format to format code with Prettier before committing

Files:

  • packages/suite/src/views/wallet/staking/components/CardanoNewProviderCard.tsx
  • suite-common/wallet-core/src/stake/stakeReducer.ts
  • packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeInANutshellModal/StakeInANutshellModal.tsx
  • suite-common/wallet-constants/src/cardanoConstants.ts
  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/NewProviderCard.tsx
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardAccountRow.tsx
  • suite-common/wallet-types/src/cardanoStaking.ts
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardActivateRow.tsx
  • packages/suite/src/views/wallet/staking/components/EthStakingDashboard/components/EthStakingDashboard.tsx
  • packages/suite/src/components/wallet/WalletLayout/AccountBanners/StakingBanner.tsx
  • suite-common/wallet-core/src/stake/stakeConstants.ts
  • suite-common/wallet-utils/src/cardanoStakingUtils.ts
  • packages/suite/src/views/wallet/staking/components/SolStakingDashboard/SolStakingDashboard.tsx
  • suite-common/wallet-core/src/stake/stakeSelectors.ts
  • packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeModal/StakeInfoCards/EstimatedGains.tsx
  • suite-common/wallet-core/src/stake/stakeThunks.ts
  • packages/suite/src/hooks/wallet/useCardanoStaking.ts
  • packages/suite/src/components/suite/StakingProcess/StakingInfo.tsx
  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/EmptyStakingCard.tsx
  • packages/suite-desktop-core/src/config.ts
  • packages/suite/src/components/wallet/WalletLayout/AccountsMenu/AccountItem/AccountRow/AccountItemContent/AccountItemContent.tsx
  • suite-native/staking/src/selectors.ts
  • suite-common/wallet-core/src/stake/stakeTypes.ts
  • packages/suite/src/views/wallet/staking/components/CardanoStakingDashboard/NewCardanoStakingDashboard.tsx
  • suite-native/staking/src/solanaStakingSelectors.ts
  • packages/suite/src/actions/wallet/stake/stakeFormCardanoActions.ts
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboard.tsx
🧠 Learnings (5)
📚 Learning: 2025-11-10T09:22:18.490Z
Learnt from: tomasklim
Repo: trezor/trezor-suite PR: 22729
File: packages/suite/src/actions/wallet/selectedAccountActions.ts:184-190
Timestamp: 2025-11-10T09:22:18.490Z
Learning: In the trezor-suite repository, exchange (swap) routes should not use selectedAccount from Redux. Exchange components use the useTradingFormAccount hook to derive the account independently, and syncSelectedAccount is intentionally skipped for routes starting with 'wallet-trading-exchange' to prevent unnecessary Redux updates during the global swap flow.

Applied to files:

  • packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeInANutshellModal/StakeInANutshellModal.tsx
  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/NewProviderCard.tsx
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardAccountRow.tsx
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardActivateRow.tsx
  • packages/suite/src/views/wallet/staking/components/EthStakingDashboard/components/EthStakingDashboard.tsx
  • packages/suite/src/components/wallet/WalletLayout/AccountBanners/StakingBanner.tsx
  • packages/suite/src/views/wallet/staking/components/SolStakingDashboard/SolStakingDashboard.tsx
  • packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeModal/StakeInfoCards/EstimatedGains.tsx
  • packages/suite/src/hooks/wallet/useCardanoStaking.ts
  • packages/suite/src/components/wallet/WalletLayout/AccountsMenu/AccountItem/AccountRow/AccountItemContent/AccountItemContent.tsx
  • suite-native/staking/src/solanaStakingSelectors.ts
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboard.tsx
📚 Learning: 2025-03-25T08:57:21.694Z
Learnt from: vojtatranta
Repo: trezor/trezor-suite PR: 17644
File: packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/IODetails/TransactionDetailsModal.tsx:87-112
Timestamp: 2025-03-25T08:57:21.694Z
Learning: Missing React keys in iterables in the `TransactionDetailsModal.tsx` file are accepted by the project maintainers, specifically in the token transfers mapping.

Applied to files:

  • packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeInANutshellModal/StakeInANutshellModal.tsx
  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/NewProviderCard.tsx
  • packages/suite/src/views/wallet/staking/components/EthStakingDashboard/components/EthStakingDashboard.tsx
  • packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeModal/StakeInfoCards/EstimatedGains.tsx
📚 Learning: 2025-02-04T13:18:21.530Z
Learnt from: jbazant
Repo: trezor/trezor-suite PR: 16668
File: suite-native/module-trading/src/components/TradeableAssetsSheet/TradeableAssetsSheet.tsx:0-0
Timestamp: 2025-02-04T13:18:21.530Z
Learning: The mock data arrays in `suite-native/module-trading/src/components/TradeableAssetsSheet/TradeableAssetsSheet.tsx` are intentionally used as visual stubs and will be replaced with real data fetching in future commits.

Applied to files:

  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/NewProviderCard.tsx
  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardAccountRow.tsx
  • packages/suite/src/views/wallet/staking/components/EthStakingDashboard/components/EthStakingDashboard.tsx
  • packages/suite/src/components/suite/StakingProcess/StakingInfo.tsx
  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/EmptyStakingCard.tsx
📚 Learning: 2025-02-04T13:18:46.084Z
Learnt from: jbazant
Repo: trezor/trezor-suite PR: 16668
File: suite-native/module-trading/src/components/general/TradeableAssetsSheet/TradeableAssetsFilterTabs.tsx:17-28
Timestamp: 2025-02-04T13:18:46.084Z
Learning: The mock data in TradeableAssetsFilterTabs.tsx is part of a visual stub and will be replaced with dynamic data in future commits.

Applied to files:

  • packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardAccountRow.tsx
  • packages/suite/src/views/wallet/staking/components/StakingDashboard/components/EmptyStakingCard.tsx
📚 Learning: 2025-10-08T21:10:41.455Z
Learnt from: vytick
Repo: trezor/trezor-suite PR: 22340
File: suite-native/module-settings/src/components/ConnectionSettings.tsx:37-40
Timestamp: 2025-10-08T21:10:41.455Z
Learning: In Trezor Suite Native, initialized devices (including view-only) always have at least one account because the app asks users to select at least one network during initialization and discovers at least one empty account. This means `selectIsDiscoveredDeviceAccountless` returns false for all initialized devices.

Applied to files:

  • suite-native/staking/src/solanaStakingSelectors.ts
🧬 Code graph analysis (23)
packages/suite/src/views/wallet/staking/components/CardanoNewProviderCard.tsx (2)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectCardanoPoolsInfo (49-50)
suite-common/wallet-utils/src/cardanoStakingUtils.ts (1)
  • isCardanoStakedWithEverstake (35-47)
suite-common/wallet-core/src/stake/stakeReducer.ts (1)
suite-common/wallet-core/src/stake/stakeTypes.ts (1)
  • EverstakeStakingInfo (131-134)
packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeInANutshellModal/StakeInANutshellModal.tsx (2)
suite-common/wallet-core/src/stake/stakeReducer.ts (1)
  • StakeRootState (62-62)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
packages/suite/src/views/wallet/staking/components/StakingDashboard/components/NewProviderCard.tsx (1)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardAccountRow.tsx (1)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardActivateRow.tsx (1)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
packages/suite/src/views/wallet/staking/components/EthStakingDashboard/components/EthStakingDashboard.tsx (1)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
packages/suite/src/components/wallet/WalletLayout/AccountBanners/StakingBanner.tsx (1)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
suite-common/wallet-utils/src/cardanoStakingUtils.ts (2)
suite-common/wallet-types/src/cardanoStaking.ts (1)
  • CardanoPoolInfo (75-79)
suite-common/wallet-constants/src/cardanoConstants.ts (1)
  • CARDANO_POOL_SATURATION_SAFE_THRESHOLD (27-27)
packages/suite/src/views/wallet/staking/components/SolStakingDashboard/SolStakingDashboard.tsx (2)
suite-common/wallet-core/src/stake/stakeReducer.ts (1)
  • StakeRootState (62-62)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
suite-common/wallet-core/src/stake/stakeSelectors.ts (3)
suite-common/wallet-core/src/stake/stakeReducer.ts (1)
  • StakeRootState (62-62)
suite-common/wallet-constants/src/cardanoConstants.ts (1)
  • BACKUP_CARDANO_APY (3-3)
suite-common/wallet-constants/src/ethereumStakingConstants.ts (1)
  • BACKUP_ETH_APY (4-4)
packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeModal/StakeInfoCards/EstimatedGains.tsx (2)
suite-common/wallet-core/src/stake/stakeReducer.ts (1)
  • StakeRootState (62-62)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
suite-common/wallet-core/src/stake/stakeThunks.ts (3)
suite-common/wallet-core/src/stake/stakeTypes.ts (3)
  • EverstakeStakingInfo (131-134)
  • EVERSTAKE_ASSET_ENDPOINT_TYPES (34-40)
  • CardanoValidatorStats (136-151)
suite-common/wallet-core/src/stake/stakeConstants.ts (2)
  • EVERSTAKE_ENDPOINT_PREFIX (7-16)
  • EVERSTAKE_API_KEY (22-22)
suite-common/wallet-utils/src/cardanoStakingUtils.ts (1)
  • isSupportedAdaStakingNetworkSymbol (17-21)
packages/suite/src/hooks/wallet/useCardanoStaking.ts (2)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectCardanoPoolsInfo (49-50)
suite-common/wallet-utils/src/cardanoStakingUtils.ts (1)
  • selectBestCardanoPool (56-85)
packages/suite/src/components/suite/StakingProcess/StakingInfo.tsx (2)
suite-common/wallet-core/src/stake/stakeReducer.ts (1)
  • StakeRootState (62-62)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
packages/suite/src/views/wallet/staking/components/StakingDashboard/components/EmptyStakingCard.tsx (1)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
packages/suite/src/components/wallet/WalletLayout/AccountsMenu/AccountItem/AccountRow/AccountItemContent/AccountItemContent.tsx (2)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectCardanoPoolsInfo (49-50)
suite-common/wallet-utils/src/cardanoStakingUtils.ts (1)
  • isCardanoStakedWithEverstake (35-47)
suite-native/staking/src/selectors.ts (1)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
suite-common/wallet-core/src/stake/stakeTypes.ts (1)
suite-common/wallet-types/src/cardanoStaking.ts (1)
  • CardanoPoolInfo (75-79)
packages/suite/src/views/wallet/staking/components/CardanoStakingDashboard/NewCardanoStakingDashboard.tsx (2)
suite-common/wallet-core/src/stake/stakeSelectors.ts (2)
  • selectPoolStatsApyData (23-47)
  • selectCardanoPoolsInfo (49-50)
suite-common/wallet-utils/src/cardanoStakingUtils.ts (1)
  • isCardanoStakedWithEverstake (35-47)
suite-native/staking/src/solanaStakingSelectors.ts (2)
suite-common/wallet-core/src/accounts/accountsSelectors.ts (1)
  • selectAccountByKey (123-130)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectPoolStatsApyData (23-47)
packages/suite/src/actions/wallet/stake/stakeFormCardanoActions.ts (3)
suite-common/wallet-types/src/cardanoStaking.ts (1)
  • CardanoPoolInfo (75-79)
suite-common/wallet-utils/src/cardanoStakingUtils.ts (1)
  • selectBestCardanoPool (56-85)
suite-common/wallet-core/src/stake/stakeSelectors.ts (1)
  • selectCardanoPoolsInfo (49-50)
packages/suite/src/views/dashboard/StakingDashboard/StakingDashboard.tsx (3)
suite-common/wallet-config/src/types.ts (1)
  • NetworkSymbol (4-29)
suite-native/trading-fixtures/src/__fixtures__/accounts.ts (1)
  • accounts (3-80)
packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardActivateRow.tsx (1)
  • StakingDashboardActivateRow (13-75)
🪛 Gitleaks (8.29.0)
suite-common/wallet-core/src/stake/stakeConstants.ts

[high] 22-22: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Agent
  • GitHub Check: CodeQL analysis (javascript-typescript)
🔇 Additional comments (28)
suite-native/staking/src/solanaStakingSelectors.ts (1)

60-63: APY selector correctly migrated to account-based API

Using selectAccountByKey and passing the resolved account into selectPoolStatsApyData aligns with the new (state, account) signature and keeps the 0 fallback for missing accounts simple and safe for downstream callers (e.g., .toString() in selectExpectedRewardsForEpoch). Looks good.

packages/suite/src/views/wallet/staking/components/StakingDashboard/components/EmptyStakingCard.tsx (1)

54-78: Account-based APY selector usage looks correct

Passing the full account into selectPoolStatsApyData aligns with the new selector signature and correctly drives Cardano pool–aware APY without changing the surrounding logic.

packages/suite-desktop-core/src/config.ts (1)

18-44: Everstake Cardano stats domain whitelisting is consistent

Adding stats.everstake.one to allowedDomains matches the pattern of existing Everstake endpoints and should safely enable the new Cardano stats calls.

packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardActivateRow.tsx (1)

13-21: Account-based activate row wiring is consistent

Switching StakingDashboardActivateRow to accept account?: Account and deriving symbol plus APY from that account is consistent with the new selectors; when no matching account exists symbol is falsy, so the row correctly renders nothing.

packages/suite/src/views/dashboard/StakingDashboard/StakingDashboard.tsx (1)

71-73: Updated activate rows to pass accounts matches new API

Using getAccountBySymbol to feed an Account into StakingDashboardActivateRow matches the component’s new props and keeps the activation CTA at the network level (first matching account per symbol).

Also applies to: 213-221

packages/suite/src/views/dashboard/StakingDashboard/StakingDashboardAccountRow.tsx (1)

27-27: APY selector now correctly uses the full account

Passing the account into selectPoolStatsApyData is the right move for pool-aware APY (especially for Cardano) and keeps the rest of the reward calculations unchanged.

packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeInANutshellModal/StakeInANutshellModal.tsx (1)

107-113: Stake-in-a-nutshell now uses account-aware APY

Using selectPoolStatsApyData(state, account) makes the modal’s APY copy consistent with the actual staked pool (or backup APY when account/pool data is missing), without changing the surrounding flow.

packages/suite/src/views/wallet/staking/components/SolStakingDashboard/SolStakingDashboard.tsx (1)

43-47: Sol staking APY wiring matches the new selector contract

Passing the account into selectPoolStatsApyData correctly adapts the Sol staking dashboard to the account-based APY selector without affecting existing layout or control flow.

packages/suite/src/views/wallet/staking/components/EthStakingDashboard/components/EthStakingDashboard.tsx (1)

51-51: LGTM! APY selector updated to use account object.

The change from passing account?.symbol to account aligns with the refactored selectPoolStatsApyData signature. This enables Cardano APY lookups to access pool-specific data via account.misc.staking.poolId.

suite-native/staking/src/selectors.ts (1)

169-169: LGTM! Consistent with the account-based APY selector pattern.

The update correctly passes the full account object to selectPoolStatsApyData, enabling pool-specific APY calculation for Cardano staking.

suite-common/wallet-types/src/cardanoStaking.ts (1)

75-79: LGTM! Well-structured type for Cardano pool information.

The CardanoPoolInfo interface appropriately captures the essential pool metrics (APY, saturation, ID) needed for dynamic pool selection and rebalancing logic.

packages/suite/src/components/suite/StakingProcess/StakingInfo.tsx (1)

137-137: LGTM! APY selector updated consistently.

The change to pass the full account object enables Cardano pool-specific APY calculation while maintaining type safety.

packages/suite/src/components/wallet/WalletLayout/AccountsMenu/AccountItem/AccountRow/AccountItemContent/AccountItemContent.tsx (1)

3-3: LGTM! Cardano pool integration for staking status.

The changes correctly integrate Cardano pool information to determine Everstake staking status. The isCardanoStakedWithEverstake utility safely handles empty or undefined pool arrays, and the icon display logic properly reflects the staking state.

Also applies to: 48-48, 53-53

suite-common/wallet-constants/src/cardanoConstants.ts (2)

27-27: LGTM! Reasonable saturation threshold for pool selection.

The 80% saturation threshold provides a sensible safety margin for pool selection logic, helping users avoid oversaturated pools while maintaining flexibility.


3-3: Cardano APY value of 2.16% is reasonable and aligns with current market conditions.

Based on current data, Cardano staking APY in 2025 ranges approximately 1.5%–4%, with platforms like StakingRewards reporting ~2.46% and Coinbase showing ~1.59%. The updated value of 2.16% falls comfortably within this range and is more accurate than the previous 4.5%, which exceeded current market rates. This change appropriately reflects lower staking rewards in the current Cardano environment and is suitable for a backup fallback value.

packages/suite/src/views/wallet/staking/components/StakingDashboard/components/NewProviderCard.tsx (1)

20-20: LGTM! APY selector updated consistently.

The change correctly passes the full account object to enable pool-specific APY calculation for Cardano accounts.

packages/suite/src/components/wallet/WalletLayout/AccountBanners/StakingBanner.tsx (1)

47-47: LGTM! APY selector updated consistently.

The change aligns with the repository-wide refactor to pass account objects for pool-aware APY calculation, particularly benefiting Cardano staking.

suite-common/wallet-core/src/stake/stakeReducer.ts (1)

12-17: Everstake stakingInfo type narrowing looks consistent

Switching stakingInfo.data to EverstakeStakingInfo and wiring the new type into imports aligns with the richer ADA pool data and existing thunk payloads. The pending/rejected branches still initializing data to {} are safe given the optional fields, and selectors already guard against missing values.

Also applies to: 47-47

packages/suite/src/views/wallet/staking/components/CardanoNewProviderCard.tsx (1)

5-6: Using Cardano pool list for Everstake check is appropriate

Selecting cardanoStakingPools via selectCardanoPoolsInfo and passing it into isCardanoStakedWithEverstake(account, cardanoStakingPools) matches the updated helper signature and ensures the banner logic tracks the actual Everstake-managed pools rather than a hardcoded pool id.

Also applies to: 20-21

packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/StakeModal/StakeInfoCards/EstimatedGains.tsx (1)

39-39: Account‑based APY selector usage is correct

Passing the full account into selectPoolStatsApyData matches the updated selector signature and allows Cardano APY to be resolved from the currently delegated pool rather than a symbol‑level default.

packages/suite/src/views/wallet/staking/components/CardanoStakingDashboard/NewCardanoStakingDashboard.tsx (1)

7-10: Dashboard wiring to pool‑aware APY and Everstake pools is consistent

Using selectPoolStatsApyData(state, account) and feeding cardanoStakingPools into isCardanoStakedWithEverstake(account, cardanoStakingPools) cleanly aligns the Cardano dashboard with the new pool‑aware staking model. Gating <ApyCard>’s apy prop on isStakedWithEverstake || hasPendingTx preserves the existing UX while leveraging the dynamic pool list.

Also applies to: 45-46, 49-51

suite-common/wallet-core/src/stake/stakeTypes.ts (1)

6-7: New Everstake/Cardano staking types align with reducer and selector usage

Importing CardanoPoolInfo, expanding EVERSTAKE_ASSET_ENDPOINT_TYPES.StakingInfo to a per‑symbol map, and introducing EverstakeStakingInfo (with apy and pools?: CardanoPoolInfo[]) plus CardanoValidatorStats line up with how stakingInfo.data is now typed and consumed in reducers/selectors. The shapes look consistent with the rest of the staking code.

Also applies to: 35-40, 131-151

packages/suite/src/hooks/wallet/useCardanoStaking.ts (1)

4-8: Guard delegation against missing Cardano pool selection

selectBestCardanoPool(cardanoPools) can return undefined when pools have not loaded or the API returns an empty list, but prepareTxPlan still calls:

const pool = selectBestCardanoPool(cardanoPools);
let certificates =
    action === 'delegate'
        ? getDelegationCertificates(stakingPath, pool?.hex, !isStakingActive)
        : [];

This means a delegate action may attempt to build certificates with an undefined pool id, leading to opaque failures bubbling up as generic sign/compose errors.

Consider explicitly handling the “no pool” case for delegate actions, for example:

 const pool = selectBestCardanoPool(cardanoPools);

- let certificates =
-     action === 'delegate'
-         ? getDelegationCertificates(stakingPath, pool?.hex, !isStakingActive)
-         : [];
+ if (action === 'delegate' && !pool) {
+     // surface a clear reason; caught by existing try/catch and UI mapping
+     throw new Error('POOL_ID_FETCH_FAIL');
+ }
+
+ let certificates =
+     action === 'delegate'
+         ? getDelegationCertificates(stakingPath, pool.hex, !isStakingActive)
+         : [];

This keeps delegation disabled (or fails with a specific, translatable reason) until Everstake pools are available, instead of silently relying on pool?.hex being truthy.

Also applies to: 22-23, 74-75, 135-140, 184-185

⛔ Skipped due to learnings
Learnt from: vojtatranta
Repo: trezor/trezor-suite PR: 16760
File: packages/suite/src/views/wallet/transactions/TransactionList/TransactionList.tsx:105-107
Timestamp: 2025-02-11T09:53:11.461Z
Learning: Error handling for transaction fetching operations in the Trezor Suite is managed at the thunk layer rather than in the component layer.
suite-common/wallet-core/src/stake/stakeSelectors.ts (2)

23-29: LGTM - Breaking API change from symbol to account parameter.

The refactored signature correctly derives symbol and misc from the account object. Callers across the codebase will need to pass account objects instead of account.symbol.


35-44: ADA staking APY resolution logic looks correct.

The implementation properly handles:

  • Missing staking info in misc → falls back to BACKUP_CARDANO_APY
  • Pool not found by poolId → falls back to BACKUP_CARDANO_APY
  • Pool with non-positive APY → falls back to BACKUP_CARDANO_APY

Minor observation: Line 43 uses currentPool?.apy with optional chaining, but currentPool is guaranteed to be truthy at that point due to the check on line 41. This is harmless but redundant.

suite-common/wallet-core/src/stake/stakeThunks.ts (3)

116-120: API key exposed in client-side code.

The EVERSTAKE_API_KEY is included in the request headers and will be visible in network requests from the browser/app. Ensure this is intentional and that the key is scoped appropriately (read-only, rate-limited, etc.) for public exposure.


86-95: LGTM - Endpoint parameters updated for new Cardano API.

The change from name=cardano to limit=1000&offset=0&partner=Trezor aligns with the new stats.everstake.one endpoint format.


97-143: Return type correctly updated to EverstakeStakingInfo.

The thunk now properly returns either { pools: [...] } for ADA or { apy: number } for SOL, matching the EverstakeStakingInfo interface which has both fields as optional.

const hasPendingTx = useSelector(state => hasPendingStakeTypeTransaction(state, account.key));
const isStakedWithEverstake = isCardanoStakedWithEverstake(account) || hasPendingTx;
const cardanoStakingPools = useSelector(selectCardanoPoolsInfo);
const isStakedWithEverstake =
Copy link
Contributor

Choose a reason for hiding this comment

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

This is confusing, why is hasPendingTx part of isStakedWithEverstake variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I remember it correctly, there is a case where after staking we show the Cardano dashboard, but isCardanoStakedWithEverstake is still false since tx is in the pending state. That's why hasPendingTx was added here. I renamed this to avoid confusion. 45eff80

@dev-pvl dev-pvl force-pushed the feat/cardano-pool-rebalancing branch from 664a418 to 3d480fd Compare November 26, 2025 15:19
@tomasklim tomasklim removed this from Suite Nov 27, 2025
@dev-pvl dev-pvl force-pushed the feat/cardano-pool-rebalancing branch 3 times, most recently from 6aaf862 to 31ba307 Compare November 27, 2025 11:09
@tomasklim
Copy link
Member

Please squash and rebase

@dev-pvl dev-pvl force-pushed the feat/cardano-pool-rebalancing branch from 31ba307 to b50f3bc Compare November 27, 2025 11:42
Copy link
Member

@tomasklim tomasklim left a comment

Choose a reason for hiding this comment

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

Pools without active staking now show Update to Everstake
This branch:
Screenshot 2025-11-27 at 12 41 22

Dev:
Screenshot 2025-11-27 at 12 42 44

@dev-pvl dev-pvl force-pushed the feat/cardano-pool-rebalancing branch from b50f3bc to ae78896 Compare November 27, 2025 12:19
@dev-pvl
Copy link
Contributor Author

dev-pvl commented Nov 27, 2025

It should be fixed now
image

@tomasklim tomasklim enabled auto-merge (rebase) November 27, 2025 13:08
@tomasklim tomasklim disabled auto-merge November 27, 2025 13:09
@tomasklim tomasklim enabled auto-merge (rebase) November 27, 2025 13:09
auto-merge was automatically disabled November 27, 2025 15:12

Head branch was pushed to by a user without write access

@dev-pvl dev-pvl force-pushed the feat/cardano-pool-rebalancing branch from ae78896 to 07b65d4 Compare November 27, 2025 15:12
@tomasklim tomasklim merged commit 362f582 into trezor:develop Nov 27, 2025
22 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cardano staking - pool rebalancing logic

4 participants