Conversation
Introduces the Yield module, including Swift Package setup, scene, view models, and UI components for displaying yield opportunities and positions. Integrates Yield into Assets and Staking features, updates navigation, and extends transfer and primitives types to support yield actions. Adds new resources and images for yield providers, and updates dependencies and project configuration accordingly.
Deleted the unused 'name' property from GemYieldProvider and removed debug print statements from YieldSceneViewModel's fetch method for cleaner code. Updated core submodule reference.
Summary of ChangesHello @0xh3rman, 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 introduces a comprehensive 'Yield' feature, enabling users to engage with yield-generating protocols directly within the application. It establishes a new dedicated module for yield management, integrates yield information into existing asset and staking views, and extends the transaction processing system to support yield deposits and withdrawals. The changes ensure a cohesive user experience for discovering and participating in yield opportunities. Highlights
🧠 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 AssistThe 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
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 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
|
- Resolve conflicts with yield feature integration
d8c1d1b to
6b1249f
Compare
There was a problem hiding this comment.
Code Review
This pull request introduces a significant new "Yield" feature, allowing users to earn on their assets. The changes are extensive, touching multiple features to integrate this functionality, including UI additions in the Assets and Staking scenes, and core logic modifications in Transfer, Signer, and the newly created Yield and YieldService packages. My review focuses on ensuring the correctness and precision of balance calculations by advocating for the use of BigInt over Double, and on improving error handling for better debuggability. Overall, the implementation is well-structured and consistent with the existing architecture.
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolved conflicts to keep both YieldService (yielder branch) and Support/ConnectionsService (main branch) features, using appLifecycleService (renamed from observersService).
Introduce native 'earn' balance handling across the app and tidy related UI/state code. - Add earn BigInt field to Balance model and BalanceType; update BalanceViewModel total calculation. - Extend BalanceRecord DB schema and migrations to store earn/earnAmount and include earnAmount in totalAmount SQL. Update Store models and tests. - Add UpdateEarnBalance type and plumbing to UpdateBalanceType. - Implement EarnBalanceService enhancements: inject AssetsService and BalanceStore, compute total earn from positions, and write updates to BalanceStore. Add BigInt & Formatters usage and package dependency for BigInt in FeatureServices. - Wire EarnBalanceService into ServicesFactory, WalletsService and BalanceUpdateService so earn positions are updated alongside regular balances (parallel async updates). - Remove EarnPosition.name from primitives, GemstonePrimitives and store models/records; adjust mappings and table creation accordingly. - Update UI/ViewModels: make StateView public and return proper error view; refactor Earn protocols and scenes to use StateView for consistent state handling; remove local earnPositions tracking in AssetScene and read earn from assetData.balance. Add small view/model helpers (makeEarnData, delegationsViewState, etc.). - Minor: remove an observeQuery for earnPositions in AssetNavigationView, bump core submodule commit. These changes add end-to-end support for displaying and persisting 'earn' balances and unify state rendering via StateView.
* Buffer pending WebSocket messages while connecting or reconnecting (#1671) * Buffer pending WebSocket messages while connecting or reconnecting * Buffer pending WebSocket messages while connecting or reconnecting * Add do-catch with debugLog for WebSocket pending message send * Build fix (#1676) * Buffer pending WebSocket messages while connecting or reconnecting * Buffer pending WebSocket messages while connecting or reconnecting * Add do-catch with debugLog for WebSocket pending message send * Use NSLog instead of debugLog * Tron unstake fix (#1670) * Add Tron stakeData type and adjust signing Introduce a strongly-typed TronStakeData model (TronVote, TronUnfreeze, TronStakeData) in Primitives and replace the previous votes dictionary in TransactionLoadMetadata with stakeData to represent both voting and unfreeze actions. Add mapping extensions between Gemstone and Primitives for stake data, votes and unfreeze types. Update TronSigner to consume the new stakeData: create vote witness contracts from TronVote objects, handle stake/redelegate with votes, and handle unstake by signing unfreeze contracts per TronUnfreeze entries. Remove the legacy getVotes accessor and adjust minor error/message fixes. Also update the core submodule pointer. * Update core * Remove throws from map; add Tron stake types Convert several GemstonePrimitives mapping helpers to non-throwing (removed try usage): GemFreezeData.map, GemFreezeType.map, GemResource.map, GemStakeType.map, GemTransactionLoadMetadata stakeData mapping, Gemstone.TronStakeData.map and Gemstone.TronUnfreeze.map. Move TronVote/TronUnfreeze/TronStakeData definitions into Primitives/StakeType.swift with Codable conformance and custom encoding/decoding, and delete the old TronStakeData.swift. These changes simplify mapping logic and centralize Tron stake models in the Primitives package. * Update core * Add Resource.key and use it in TronSigner Introduce a computed property Resource.key that returns rawValue.uppercased(), and update TronSigner to use resource.key instead of calling rawValue.uppercased() inline. This centralizes the uppercasing logic and removes duplicated formatting across contract construction sites (Packages/Primitives/Sources/Extensions/Resource+Primitives.swift and Packages/Signer/Sources/Chains/TronSigner.swift). * Update ResourceViewModel.swift * Minor updates * Update core * Extract InputAccessoryView component for suggestions and action button (#1673) * Extract InputAccessoryView component for suggestions and action button * Move safeAreaView to Components and refactor SelectableSheet to use safeAreaButton * Resettable timer + RefreshableTimer modifier (#1674) * Refactor timers and magic time intervals into reusable constants (#1666) - Add TimerModifier with .onTimer(every:action:) view modifier - Add Interval type with time constants (seconds30, minute1, minutes5) - Add Interval.AnimationDuration constants (fast, normal, slow, verySlow) - Add Duration.Debounce constants (fast, normal, slow) - Replace inline Timer.publish/onReceive with .onTimer in existing screens - Add periodic refresh timers to TransactionsScene, AssetScene, FiatScene, PerpetualsScene - Replace hardcoded debounce durations across search and input scenes - Replace hardcoded animation durations in FloatTextField, ActivityIndicator, ChartView, PulsingDotView * Add resettable RefreshableTimerModifier and modernize timers Replace Combine-based TimerModifier with Task.sleep loop for structured concurrency. Add RefreshableTimerModifier that resets the timer countdown on pull-to-refresh, preventing redundant fetches. Migrate 5 scenes from separate .refreshable + .onTimer to unified .refreshableTimer modifier. * Fix price alert toast visibility and locale-aware price suggestions (#1680) Move toast modifier outside NavigationStack so it renders above pushed screens. Change PriceSuggestion.value to Double and format inputValue with locale-aware number formatting to avoid wrong decimal separators. * Refactor Earn protocols to providers Rename and refactor the Earn feature to use 'providers' (yield) instead of 'protocols'. Key changes: rename scenes/views/viewmodels (EarnProtocols -> EarnProviders), replace EarnProtocol model with EarnProvider and YieldProvider types, introduce EarnPositionBase and update EarnPosition to include a base property, and adapt formatting/fields (balance, shares, apy, providerId). Update EarnService API (EarnServiceable) and implementations to use YieldProvider and GemEarnPositionBase, add new GemstonePrimitives mappings, and adjust tests and factories accordingly. Persisted schema changes: update EarnPositionRecord, add EarnProviderRecord, and register migrations to create/adjust tables. Misc: project file and navigation updates, removal of legacy mapping files, and an added architecture doc (docs/earn-architecture-plan.md). * Use safeAreaView for word suggestions instead of keyboard toolbar (#1681) * Avoid pushing duplicate screens (#1675) * Avoid pushing duplicate screens - Add NavigationPathState that encapsulates NavigationPath with a shadow stack for deduplication - Replace NavigationPath properties in NavigationStateManager with NavigationPathState - Route all programmatic navigation through NavigationPathState.append which skips if the same screen is already on top * Move NavigationPathState to Components package with Codable-based duplicate detection Replace AnyHashable stack tracking with NavigationPath.CodableRepresentation encoding to detect duplicate pushes. Add Codable conformance to all Scenes types. Add unit tests. * Add Scenes.Transaction wrapper for TransactionExtended navigation Wrap TransactionExtended in Scenes.Transaction for consistent navigation pattern across all scene types pushed onto NavigationPath. * Add new stream events, NFT chain enum Introduce new streaming event types and related models to support NFTs, price alerts, perpetuals, and in-app notifications, plus realtime price subscribe messages. - Add NFTChain enum (Packages/Primitives/Sources/ChainNft.swift) (generated by typeshare). - Extend Stream types (Packages/Primitives/Sources/Stream.swift): - Remove chain and address from StreamBalanceUpdate initializer. - Change StreamTransactionsUpdate to use [TransactionId] instead of [Transaction]. - Add StreamNftUpdate, StreamPriceAlertUpdate, StreamPerpetualUpdate, StreamNotificationlUpdate. - Add StreamEvent cases: priceAlerts, nft, perpetual, inAppNotification and wire up Codable encode/decode. - Add StreamMessage realtime price cases: subscribeRealtimePrices, unsubscribeRealtimePrices and wire up Codable. - Update PriceObserverService (Packages/FeatureServices/PriceService/PriceObserverService.swift) to handle the new StreamEvent cases (no-op placeholders). - Bump core submodule commit. Migration notes: update any call sites constructing StreamBalanceUpdate or StreamTransactionsUpdate to match the new initializers/types, and handle the new StreamEvent/StreamMessage variants where applicable. * Remove SupportService and pass deviceId to Support Remove the legacy SupportService and related support-device registration plumbing, and switch to passing a deviceId string through the UI stack. Changes include: - Remove SupportService, its tests and calls to registerSupport; drop support-related preferences keys. - Propagate deviceId from Settings -> SupportSceneViewModel -> ChatwootWebViewModel and rename supportDeviceId -> deviceId; Chatwoot custom attribute uses device_id. - Remove GemAPI support endpoints/types (GemAPISupportService, addSupportDevice, GemDeviceAPI support routes) and related Support structs (NewSupportDevice, SupportDeviceRequest). - Remove Support package dependency on GemAPI and PreferencesTestKit, and update Feature package manifest. - Remove environment/service wiring and DI for SupportService across AppResolver, ServicesFactory, EnvironmentValues and view injection. - Add StreamNewAssetsUpdate and newAssets case to StreamEvent and handle in PriceObserverService. - Update core submodule commit. These changes centralize device id handling in callers and drop server-side support device registration code and state. * Fix perpetual chart showing data from wrong asset (#1684) * Fix perpetual chart showing data from wrong asset When navigating between perpetual screens, candle updates from one asset could be applied to another asset's chart. Now handleChartUpdate validates that candle.coin matches the current subscription before applying updates. * Refactor chart services to use ChartCandleUpdate - Update ChartStreamable protocol to use ChartCandleUpdate - Update ChartObserverService to stream ChartCandleUpdate - Update HyperliquidObserverService to use GemChartCandleUpdate - Update PerpetualSceneViewModel to extract candle from update - Add GemChartCandleUpdate mapping extension - Handle new StreamEvent cases in PriceObserverService * Refactor chart & push notification models Remove interval from ChartCandleStick and simplify its initializer so candles are interval-agnostic. Add ChartCandleUpdate (coin, interval, candle) to represent interval-scoped candle updates. Remove the optional walletIndex from PushNotificationTransaction and update its initializer accordingly. Also update the core submodule reference to the new commit. * Bump to 1.3.344 (45) * Set current wallet before transaction navigation Call walletService.setCurrent(for:) at the start of navigateToTransaction to ensure the active wallet context is set before fetching assets and adding the transaction. Also updates the core submodule pointer. This prevents services from operating on an incorrect or stale wallet state when navigating to a transaction. * Guard missing wallet, add getter, fix mapping Add WalletService.getWallet to expose wallet lookup and use it in NavigationHandler to guard against missing wallets before setting current and adding a transaction (prevents crashes/no-op if wallet not found). Also simplify GatewayService candlestick mapping by removing an unnecessary try when the mapped operation is nonthrowing. * Bump to 1.3.345 (46) * Delete earn-architecture-plan.md * Rename EarnData to YieldData and consolidate earn types - Rename EarnData → YieldData, EarnService → YieldService - Add YieldType with YieldTransaction from Rust core - Add EarnProviderType to DelegationValidator for yield/stake filtering - Remove EarnPosition/EarnPositionBase (use DelegationBase) - Remove EarnStore/EarnServices (consolidated into StakeStore) - Update mappers for new Gemstone yield types - Add providerType migration to stake_validators table - Remove SupportService references (not yet implemented) * Update Primitives and typeshare types for Earn rename - Add typeshare-generated EarnData, EarnType, EarnTransaction - Add GrowthProviderType (replaces EarnProviderType) - Remove old YieldData, YieldType, EarnProvider files - Update TransactionLoadMetadata with earnData accessor - Update TransferDataType and AmountType for new Earn types * Rename YieldService to EarnProviderService and update FFI mappers - Rename YieldService to EarnProviderService with TestKit mock - Update GemstonePrimitives mappers for EarnType and EarnData - Rename GemYieldData mapper to GemEarnData - Update EthereumSigner to use earnData from metadata * Update features, ViewModels, Store, and tests for Earn types - Update EarnSceneViewModel, EarnProvidersSceneViewModel, and EarnPositionViewModel to use EarnProviderService - Update AmountEarnViewModel and AmountStakeViewModel for new EarnType/EarnData structure - Update TransactionFactory to read earnData from metadata - Update ServicesFactory and ViewModelFactory references - Update Store migrations and StakeValidatorRecord for GrowthProviderType - Update core submodule pointer * Add Staking package split from Earn * Update Earn package, move staking files to Staking * In progress yield * Removed hardcoded updateEarnAssets --------- Co-authored-by: Radmir <52320354+DRadmir@users.noreply.github.com> Co-authored-by: gemcoder21 <104884878+gemcoder21@users.noreply.github.com>
…-ios into gem-ios-yielder
- Gateway: added earnProviders, earnPositions, earnBalance to GatewayService - Balance pipeline: added .earn case to AssetBalanceType, wired through BalanceFetcher → BalanceService - GemBalance.map(): now maps the earn field - Removed YieldService entirely (+ TestKit) - Removed earnService from BalanceUpdateService/WalletsService - Removed unused BigInt dep from FeatureServices/Package.swift - EarnService simplified to use gatewayService only - Updated ServicesFactory/ViewModelFactory to remove yieldService - Core submodule pointer updated
Resolved core submodule merge conflicts: - Updated testing guidelines - Adopted with_provider pattern - Updated error types Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed compilation errors: - Removed duplicate encode_with_0x function - Added missing StakeData import Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
| stakeView | ||
| } | ||
|
|
||
| if model.hasYieldPosition { |
There was a problem hiding this comment.
| if model.hasYieldPosition { | |
| if model.hasEarnPositions { |
| NavigationCustomLink( | ||
| with: HStack(spacing: .space12) { | ||
| EmojiView(color: Colors.grayVeryLight, emoji: "💰") | ||
| with: HStack(spacing: Spacing.medium) { |
There was a problem hiding this comment.
| with: HStack(spacing: Spacing.medium) { | |
| with: HStack(spacing:.medium) { |
| private func shouldShowBanner(_ banner: Banner) -> Bool { | ||
| switch banner.event { | ||
| case .enableNotifications, .accountBlockedMultiSignature, .tradePerpetuals: true | ||
| case .yield: assetData.isEarnable |
There was a problem hiding this comment.
| case .yield: assetData.isEarnable | |
| case .earn: assetData.isEarnable |
| private let transactionsService: TransactionsService | ||
| private let priceObserverService: PriceObserverService | ||
| private let bannerService: BannerService | ||
| private let yieldService: any YieldServiceType |
There was a problem hiding this comment.
| private let yieldService: any YieldServiceType | |
| private let earnService: any EarnServiceType |
| ProgressView() | ||
| Spacer() | ||
| } | ||
| .padding(.vertical, Spacing.medium) |
There was a problem hiding this comment.
| .padding(.vertical, Spacing.medium) | |
| .padding(.vertical, .medium) |
| } | ||
|
|
||
| extension TransactionLoadMetadata { | ||
| public var earnData: EarnData? { |
There was a problem hiding this comment.
| public var earnData: EarnData? { | |
| public getEarnData() throws EarnData { |
| ) | ||
| } | ||
|
|
||
| static func earn(assetId: AssetId) -> NewBanner { |
| var isActive: Bool | ||
| var commission: Double | ||
| var apr: Double | ||
| var providerType: String |
There was a problem hiding this comment.
| var providerType: String | |
| var providerType: EarnProviderType |
| try setColumn(for: assetIds, column: AssetRecord.Columns.isEarnable, value: value) | ||
| } | ||
|
|
||
| public func setEarnApr(assetId: String, apr: Double) throws { |
| } | ||
|
|
||
| @discardableResult | ||
| public func setAssetIsEarnable(for assetIds: [String], value: Bool) throws -> Int { |
Uh oh!
There was an error while loading. Please reload this page.