Skip to content

Feature: Session-Based Transaction History #3872

@realpaaao

Description

@realpaaao

Overview

Session-based transaction history that records every send and swap initiated by the user from vault import onward. No blockchain scanning - we log what the user does, not what happened externally.

Figma: Transaction History - Overview


Scope

  • All sends (native + token) on all supported chains
  • All swaps (1inch, KyberSwap, LiFi, THORChain, MayaChain) on all supported chains
  • Per-vault history with tab filtering (Overview/Swaps/Send) + basic filters (chain, token, date range)
  • Pending status tracking (poll on app open)
  • Reuse dynamic complete screen for detail/status view

Out of scope (v1): Blockchain scanning, incoming transactions (receives), token approvals, cross-vault aggregate view, export, backend sync.


Core Concept

"Session" = lifecycle from vault import (or creation) to now. The app acts as a local ledger of user-initiated actions.

  • Recorded: Every tx the user broadcasts through the app
  • NOT recorded: Txs before vault import, incoming txs, txs from other devices
  • Trade-off: Reinstalling/importing on new device starts fresh history (no server dependency)

Data Model

Common fields:

Field Type Description
id UUID Local unique identifier
vaultId String Vault that initiated the tx
type Enum send or swap
status Enum broadcasted, pending, confirmed, failed
chain String Source chain
timestamp ISO 8601 When broadcast
txHash String On-chain transaction hash
explorerUrl String Block explorer link
fiatValue String? USD value at broadcast time

Send-specific: fromAddress, toAddress, amount, token, tokenLogo, feeEstimate, memo

Swap-specific: fromToken, fromAmount, fromChain, fromTokenLogo, toToken, toAmount, toChain, toTokenLogo, provider, route

Status metadata: confirmedAt, failureReason, lastCheckedAt


Storage (iOS)

  • Engine: SwiftData (preferred) or Core Data
  • Location: App's persistent container (not caches directory - must survive cache clearing)
  • Retention: Unlimited, no auto-pruning
  • Migration: Standard lightweight migration for future schema changes
  • Schema: Single entity for transaction records, partitioned by vaultId

Recording Flow

  1. User confirms send/swap
  2. Transaction signed + broadcast
  3. Write tx record to local storage with status = broadcasted
  4. Dynamic complete screen shows (existing)
  5. Complete screen polls + updates status (existing)
  6. On status change (confirmed/failed): update local record

Integration point: Write immediately after successful broadcast, before showing the complete screen. Complete screen's status callback updates the history record.


Status Tracking

State machine: broadcasted -> pending -> confirmed / failed

During complete screen: Existing dynamic complete screen resolves status. On resolution, update history record.

After leaving complete screen (pending txs): Refresh on app open only.

  • On scenePhase == .active: query pending records, fire status checks
  • On history screen onAppear: same
  • Pull-to-refresh: same
  • Reuse existing chain status check providers from dynamic tx status feature
  • Concurrent checks (one async task per pending tx, reasonable concurrency limit)
  • No background polling. No push notifications. No polling when offline.

UI Implementation

History List Screen

  • Scrollable list using SwiftUI lazy loading
  • Tab bar: Overview | Swaps | Send as custom segmented control matching Figma (underline active indicator)
  • Transaction cards as custom views matching Figma card designs
  • Date section headers ("Today [date]", "Yesterday [date]", etc.)
  • Pull-to-refresh triggers pending tx status check

Card Views (follow Figma exactly)

In-Progress Card (swap):

  • Elevated visual treatment (border/shadow)
  • Green "Swap" badge pill, "In progress... [elapsed]" with progress bar
  • Token icons, amounts, "min. payout" label, route pill

Resolved Card (send or swap):

  • Type badge pill (blue Send, green Swap)
  • Status: "Successful" (green) or "Error" (red)
  • Token icon + fiat value + token amount
  • Address pill "to [truncated address]"

Detail View

Tapping a card navigates to the existing dynamic complete screen, passing tx data:

  • confirmed/failed: Static resolved state
  • broadcasted/pending: Active state, resumes polling

Filtering

  • Primary: Tab bar (Overview / Swaps / Send)
  • Secondary: Chain, token, date range filters

Empty State

"No transactions yet. Your sends and swaps will appear here."


Key Considerations

  • Offline: History readable offline. Status refresh only when network available.
  • VoiceOver: Accessibility labels on all card elements
  • Dynamic Type: Respect text sizing preferences
  • Dark theme: Match Figma dark theme
  • Performance: Lazy loading for 1000+ records
  • Thread safety: SwiftData writes on correct context/thread

Deliverables

  • Transaction history data model (SwiftData entity)
  • Transaction recording service (write on broadcast, update on status change)
  • History list screen (tabs, cards, date grouping, filters, pull-to-refresh)
  • Detail view integration (navigate to dynamic complete screen with tx data)
  • Pending status refresh on app foreground / history screen appear

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions