diff --git a/Features/Transactions/Tests/TransactionsTests/ViewModels/TransactionViewModelTests.swift b/Features/Transactions/Tests/TransactionsTests/ViewModels/TransactionViewModelTests.swift index 2d3ce64c8..22833832f 100644 --- a/Features/Transactions/Tests/TransactionsTests/ViewModels/TransactionViewModelTests.swift +++ b/Features/Transactions/Tests/TransactionsTests/ViewModels/TransactionViewModelTests.swift @@ -34,7 +34,7 @@ final class TransactionViewModelTests { let outgoingViewModel = TransactionViewModel.mock( type: .transfer, direction: .outgoing, - participant: "to_address", + to: "to_address", metadata: .encode(TransactionSwapMetadata.mock()) ) #expect(outgoingViewModel.participant == "to_address") @@ -42,7 +42,7 @@ final class TransactionViewModelTests { let selfTransferViewModel = TransactionViewModel.mock( type: .transfer, direction: .selfTransfer, - participant: "self_address", + to: "self_address", metadata: .encode(TransactionSwapMetadata.mock()) ) #expect(selfTransferViewModel.participant == "self_address") @@ -54,7 +54,7 @@ final class TransactionViewModelTests { let hyperliquidViewModel = TransactionViewModel.mock( type: .transfer, direction: .outgoing, - participant: "0x742d35cc6327c516e07e17dddaef8b48ca1e8c4a", + to: "0x742d35cc6327c516e07e17dddaef8b48ca1e8c4a", toAddress: toAddress, metadata: .encode(TransactionSwapMetadata.mock()) ) @@ -64,7 +64,7 @@ final class TransactionViewModelTests { let incomingViewModel = TransactionViewModel.mock( type: .transfer, direction: .incoming, - participant: "0x1111111111111111111111111111111111111111", + from: "0x1111111111111111111111111111111111111111", fromAddress: fromAddress, metadata: .encode(TransactionSwapMetadata.mock()) ) @@ -73,7 +73,7 @@ final class TransactionViewModelTests { let unknownViewModel = TransactionViewModel.mock( type: .transfer, direction: .outgoing, - participant: "0x1234567890abcdef1234567890abcdef12345678", + to: "0x1234567890abcdef1234567890abcdef12345678", metadata: .encode(TransactionSwapMetadata.mock()) ) #expect(unknownViewModel.titleExtraTextValue?.text.contains("0x1234") == true) @@ -174,6 +174,31 @@ final class TransactionViewModelTests { #expect(model.titleExtraTextValue == nil) } + @Test + func titleExtraHidesEmptyParticipant() { + let model = TransactionViewModel.mock(type: .stakeDelegate, direction: .outgoing, to: "") + + #expect(model.titleExtraTextValue == nil) + } + + @Test + func titleExtraHidesEmptySender() { + let model = TransactionViewModel( + explorerService: MockExplorerLink(), + transaction: .mock( + transaction: .mock( + type: .transfer, + direction: .incoming, + from: "", + to: "0x123" + ) + ), + currency: "USD" + ) + + #expect(model.titleExtraTextValue == nil) + } + func testTransactionTitle(expectedTitle: String, transaction: Transaction) { #expect(TransactionViewModel(explorerService: MockExplorerLink(), transaction: .mock(transaction: transaction), currency: "USD").titleTextValue.text == expectedTitle) } @@ -184,7 +209,8 @@ extension TransactionViewModel { type: TransactionType = .swap, state: TransactionState = .confirmed, direction: TransactionDirection = .incoming, - participant: String = "", + from: String = "", + to: String = "", memo: String? = nil, fromAddress: AddressName? = nil, toAddress: AddressName? = nil, @@ -197,7 +223,8 @@ extension TransactionViewModel { type: type, state: state, direction: direction, - to: participant, + from: from, + to: to, value: value, memo: memo, metadata: metadata diff --git a/Features/Transfer/Sources/ViewModels/AmountStakeViewModel.swift b/Features/Transfer/Sources/ViewModels/AmountStakeViewModel.swift index acbd31df4..d4d94eba1 100644 --- a/Features/Transfer/Sources/ViewModels/AmountStakeViewModel.swift +++ b/Features/Transfer/Sources/ViewModels/AmountStakeViewModel.swift @@ -119,7 +119,7 @@ final class AmountStakeViewModel: AmountDataProvidable { RecipientData( recipient: Recipient( name: validatorSelection.selected.name, - address: recipientAddress(validatorId: validatorSelection.selected.id), + address: validatorSelection.selected.id, memo: Localized.Stake.viagem ), amount: nil @@ -144,13 +144,4 @@ final class AmountStakeViewModel: AmountDataProvidable { canChangeValue: canChangeValue ) } - - private func recipientAddress(validatorId: String) -> String { - switch asset.chain.stakeChain { - case .cosmos, .osmosis, .injective, .sei, .celestia, .solana, .sui, .tron, .smartChain, .ethereum, .aptos, .monad: - validatorId - case .none, .hyperCore: - "" - } - } } diff --git a/Packages/PrimitivesComponents/Sources/ViewModels/TransactionViewModel.swift b/Packages/PrimitivesComponents/Sources/ViewModels/TransactionViewModel.swift index f60d185c6..3adbb83de 100644 --- a/Packages/PrimitivesComponents/Sources/ViewModels/TransactionViewModel.swift +++ b/Packages/PrimitivesComponents/Sources/ViewModels/TransactionViewModel.swift @@ -181,31 +181,15 @@ public struct TransactionViewModel: Sendable { case .transfer, .transferNFT, .tokenApproval, .smartContractCall: switch transaction.transaction.direction { case .incoming: - return String( - format: "%@ %@", - Localized.Transfer.from, - getDisplayName(address: transaction.transaction.from, chain: chain) - ) + return participantTitle(prefix: Localized.Transfer.from, address: transaction.transaction.from, chain: chain) case .outgoing, .selfTransfer: - return String( - format: "%@ %@", - Localized.Transfer.to, - getDisplayName(address: transaction.transaction.to, chain: chain) - ) + return participantTitle(prefix: Localized.Transfer.to, address: transaction.transaction.to, chain: chain) } case .stakeDelegate, .stakeRedelegate: - return String( - format: "%@ %@", - Localized.Transfer.to, - getDisplayName(address: transaction.transaction.to, chain: chain) - ) + return participantTitle(prefix: Localized.Transfer.to, address: transaction.transaction.to, chain: chain) case .stakeUndelegate: - return String( - format: "%@ %@", - Localized.Transfer.from, - getDisplayName(address: transaction.transaction.to, chain: chain) - ) + return participantTitle(prefix: Localized.Transfer.from, address: transaction.transaction.to, chain: chain) case .stakeFreeze: guard let title = getResourceTitle() else { return .none } return String(format: "%@ %@", Localized.Transfer.to, title) @@ -213,9 +197,9 @@ public struct TransactionViewModel: Sendable { guard let title = getResourceTitle() else { return .none } return String(format: "%@ %@", Localized.Transfer.from, title) case .earnDeposit: - return String(format: "%@ %@", Localized.Transfer.to, getDisplayName(address: transaction.transaction.to, chain: chain)) + return participantTitle(prefix: Localized.Transfer.to, address: transaction.transaction.to, chain: chain) case .earnWithdraw: - return String(format: "%@ %@", Localized.Transfer.from, getDisplayName(address: transaction.transaction.to, chain: chain)) + return participantTitle(prefix: Localized.Transfer.from, address: transaction.transaction.to, chain: chain) case .swap, .stakeRewards, .stakeWithdraw, @@ -365,12 +349,19 @@ public struct TransactionViewModel: Sendable { // MARK: - Private methods private func getDisplayName(address: String, chain: Chain) -> String { + guard address.isNotEmpty else { return "" } if let name = getAddressName(address: address)?.name { return name } return AddressFormatter(address: address, chain: chain).value() } + private func participantTitle(prefix: String, address: String, chain: Chain) -> String? { + let value = getDisplayName(address: address, chain: chain) + guard value.isNotEmpty else { return nil } + return String(format: "%@ %@", prefix, value) + } + private func getResourceTitle() -> String? { guard let resourceType = transaction.transaction.metadata?.decode(TransactionResourceTypeMetadata.self)?.resourceType else { return nil } return ResourceViewModel(resource: resourceType).title