SPB Git

spb/os-vault Public

Self-custody, multi-chain crypto wallet for macOS. One recovery phrase, six chain families, zero API keys — nothing leaves your Mac.

Swift 96% Shell 3.4% Makefile 0.6%
2.7 KB · 86 lines swift
Raw Blame History
1//2//  TransactionRecord.swift3//  OS Vault4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//89import Foundation10import BigInt1112/// A send initiated from this app, persisted locally (non-sensitive data13/// only: it is all public on-chain anyway). Full history lives on the14/// explorer; each record links there.15public struct TransactionRecord: Identifiable, Codable, Equatable {16    public enum Status: String, Codable {17        case pending, confirmed, failed18    }1920    public let id: UUID21    public let hash: String22    public let tokenSymbol: String23    public let tokenDecimals: Int24    public let amountUnits: String          // BigUInt as decimal string (Codable-safe)25    public let recipient: String26    public let network: Network27    public var status: Status28    public let date: Date2930    public init(hash: String, asset: Asset, amountUnits: BigUInt,31                recipient: String, network: Network, status: Status, date: Date = Date()) {32        self.id = UUID()33        self.hash = hash34        self.tokenSymbol = asset.symbol(on: network)35        self.tokenDecimals = asset.decimals36        self.amountUnits = String(amountUnits)37        self.recipient = recipient38        self.network = network39        self.status = status40        self.date = date41    }4243    public var displayAmount: String {44        guard let units = BigUInt(amountUnits, radix: 10) else { return amountUnits }45        return TokenAmount.format(units, decimals: tokenDecimals)46    }4748    public var explorerURL: URL { network.explorerTxURL(hash) }49}5051/// JSON-file persistence for local send history.52public final class HistoryStore {53    private let fileURL: URL54    private let maxEntries = 2005556    public init(fileURL: URL? = nil) {57        if let fileURL {58            self.fileURL = fileURL59        } else {60            let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]61            self.fileURL = support.appendingPathComponent("OSVault/history.json")62        }63    }6465    public func load() -> [TransactionRecord] {66        guard let data = try? Data(contentsOf: fileURL),67              let records = try? JSONDecoder().decode([TransactionRecord].self, from: data) else {68            return []69        }70        return records71    }7273    public func save(_ records: [TransactionRecord]) {74        let trimmed = Array(records.prefix(maxEntries))75        let dir = fileURL.deletingLastPathComponent()76        try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)77        if let data = try? JSONEncoder().encode(trimmed) {78            try? data.write(to: fileURL, options: [.atomic])79        }80    }8182    public func clear() {83        try? FileManager.default.removeItem(at: fileURL)84    }85}86