diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/confirm/BuildConfirmPropertiesImpl.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/confirm/BuildConfirmPropertiesImpl.kt index e8c760dac..8f54a4d7b 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/confirm/BuildConfirmPropertiesImpl.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/confirm/BuildConfirmPropertiesImpl.kt @@ -33,22 +33,28 @@ class BuildConfirmPropertiesImpl( add(ConfirmProperty.Source(assetInfo.walletName)) val destination = ConfirmProperty.Destination.map(request, getValidator(request)) add( - if (destination is ConfirmProperty.Destination.Transfer) { - ConfirmProperty.Destination.Transfer( + when (destination) { + is ConfirmProperty.Destination.Transfer -> ConfirmProperty.Destination.Transfer( domain = destination.domain, address = destination.address, explorerLink = BlockExplorerLink(explorerName, chainExplorer.getAddressUrl(explorerName, destination.address)), ) - } else { - destination + is ConfirmProperty.Destination.Stake -> destination.address?.let { address -> + ConfirmProperty.Destination.Stake( + data = destination.data, + address = address, + explorerLink = BlockExplorerLink(explorerName, chainExplorer.getAddressUrl(explorerName, address)), + ) + } ?: destination + else -> destination } ) + add(ConfirmProperty.Network(assetInfo.chain.asset())) add(request.memo()?.takeIf { (request is ConfirmParams.TransferParams.Native || request is ConfirmParams.TransferParams.Token) && assetInfo.asset.isMemoSupport() && it.isNotEmpty() }?.let { ConfirmProperty.Memo(it) }) - add(ConfirmProperty.Network(assetInfo.chain.asset())) }.filterNotNull() } @@ -58,8 +64,8 @@ class BuildConfirmPropertiesImpl( is ConfirmParams.Stake.RedelegateParams -> params.destinationValidator.id is ConfirmParams.Stake.UndelegateParams -> params.delegation.base.validatorId is ConfirmParams.Stake.WithdrawParams -> params.delegation.base.validatorId + is ConfirmParams.Stake.RewardsParams -> params.validators.singleOrNull()?.id is ConfirmParams.Activate, - is ConfirmParams.Stake.RewardsParams, is ConfirmParams.Stake.Freeze, is ConfirmParams.Stake.Unfreeze, is ConfirmParams.SwapParams, diff --git a/android/features/confirm/presents/src/main/kotlin/com/gemwallet/android/features/confirm/presents/components/PropertyDestination.kt b/android/features/confirm/presents/src/main/kotlin/com/gemwallet/android/features/confirm/presents/components/PropertyDestination.kt index c4cdfbe0c..a417fa3a0 100644 --- a/android/features/confirm/presents/src/main/kotlin/com/gemwallet/android/features/confirm/presents/components/PropertyDestination.kt +++ b/android/features/confirm/presents/src/main/kotlin/com/gemwallet/android/features/confirm/presents/components/PropertyDestination.kt @@ -44,12 +44,34 @@ fun PropertyDestination( ) } } + is ConfirmProperty.Destination.Stake -> { + val address = model.address + if (address != null && model.explorerLink != null) { + AddressPropertyItem( + title = R.string.stake_validator, + displayText = model.displayData(), + copyValue = address, + explorerLink = model.explorerLink, + listPosition = listPosition, + ) + } else { + PropertyItem( + title = { PropertyTitleText(R.string.stake_validator) }, + data = { + Column(horizontalAlignment = Alignment.End) { + Row(horizontalArrangement = Arrangement.End) { PropertyDataText(model.displayData()) } + } + }, + listPosition = listPosition, + ) + } + } else -> { val title = when (model) { is ConfirmProperty.Destination.Provider -> R.string.common_provider - is ConfirmProperty.Destination.Stake -> R.string.stake_validator is ConfirmProperty.Destination.Generic -> R.string.wallet_connect_app is ConfirmProperty.Destination.PerpetualOper -> R.string.common_provider + is ConfirmProperty.Destination.Stake, is ConfirmProperty.Destination.Transfer -> return } PropertyItem( diff --git a/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmProperty.kt b/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmProperty.kt index 3e19f5303..a98f157be 100644 --- a/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmProperty.kt +++ b/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmProperty.kt @@ -11,7 +11,7 @@ sealed interface ConfirmProperty { class Memo(val data: String) : ConfirmProperty sealed class Destination(val data: String) : ConfirmProperty { - class Stake(data: String) : Destination(data) + class Stake(data: String, val address: String? = null, val explorerLink: BlockExplorerLink? = null) : Destination(data) class Provider(data: String) : Destination(data) class Transfer(val domain: String?, val address: String, val explorerLink: BlockExplorerLink? = null) : Destination(address) class Generic(val appName: String) : Destination(appName) @@ -22,15 +22,17 @@ sealed interface ConfirmProperty { is ConfirmParams.Activate, is ConfirmParams.Stake.Freeze, is ConfirmParams.Stake.Unfreeze, - is ConfirmParams.Stake.RewardsParams, is ConfirmParams.PerpetualParams.Open, is ConfirmParams.PerpetualParams.Close, is ConfirmParams.PerpetualParams.Modify, is ConfirmParams.SwapParams -> null + is ConfirmParams.Stake.RewardsParams -> validator + ?.takeIf { params.validators.size == 1 } + ?.let { Stake(data = it.name, address = it.id) } is ConfirmParams.Stake.DelegateParams, is ConfirmParams.Stake.RedelegateParams, is ConfirmParams.Stake.UndelegateParams, - is ConfirmParams.Stake.WithdrawParams -> Stake(data = validator?.name ?: "") + is ConfirmParams.Stake.WithdrawParams -> Stake(data = validator?.name ?: "", address = validator?.id) is ConfirmParams.TokenApprovalParams -> Provider(data = params.provider) is ConfirmParams.NftParams, is ConfirmParams.TransferParams.Token, diff --git a/ios/Features/Stake/Sources/ViewModels/DelegationSceneViewModel.swift b/ios/Features/Stake/Sources/ViewModels/DelegationSceneViewModel.swift index f55cf5f3d..919433bfd 100644 --- a/ios/Features/Stake/Sources/ViewModels/DelegationSceneViewModel.swift +++ b/ios/Features/Stake/Sources/ViewModels/DelegationSceneViewModel.swift @@ -186,7 +186,7 @@ extension DelegationSceneViewModel { TransferData( type: .stake(asset, .rewards([model.delegation.validator])), recipientData: RecipientData( - recipient: Recipient(name: .none, address: "", memo: .none), + recipient: Recipient(name: model.delegation.validator.name, address: model.delegation.validator.id, memo: .none), amount: .none, ), value: model.delegation.base.rewardsValue, diff --git a/ios/Features/Stake/Sources/ViewModels/StakeSceneViewModel.swift b/ios/Features/Stake/Sources/ViewModels/StakeSceneViewModel.swift index ac6d89dc6..f6f59b362 100644 --- a/ios/Features/Stake/Sources/ViewModels/StakeSceneViewModel.swift +++ b/ios/Features/Stake/Sources/ViewModels/StakeSceneViewModel.swift @@ -161,10 +161,16 @@ public final class StakeSceneViewModel { var claimRewardsDestination: any Hashable { if canClaimAllRewards { + let validators = delegationsWithRewards.map(\.validator) + let recipient: Recipient = if validators.count == 1, let validator = validators.first { + Recipient(name: validator.name, address: validator.id, memo: .none) + } else { + Recipient(name: .none, address: "", memo: .none) + } return TransferData( - type: .stake(chain.chain.asset, .rewards(delegationsWithRewards.map(\.validator))), + type: .stake(chain.chain.asset, .rewards(validators)), recipientData: RecipientData( - recipient: Recipient(name: .none, address: "", memo: .none), + recipient: recipient, amount: .none, ), value: rewardsValue, @@ -186,15 +192,11 @@ public final class StakeSceneViewModel { } var freezeDestination: any Hashable { - destination( - type: .freeze(resource: .bandwidth), - ) + destination(type: .freeze(resource: .bandwidth),) } var unfreezeDestination: any Hashable { - destination( - type: .unfreeze(resource: .bandwidth), - ) + destination(type: .unfreeze(resource: .bandwidth),) } var showFreeze: Bool { chain == .tron } @@ -207,10 +209,7 @@ public final class StakeSceneViewModel { } var isStakeEnabled: Bool { validators.isNotEmpty } - - var showTronResources: Bool { - balanceModel.hasStakingResources - } + var showTronResources: Bool { balanceModel.hasStakingResources } } // MARK: - Business Logic diff --git a/ios/Features/Transfer/Sources/ViewModels/ConfirmRecipientViewModel.swift b/ios/Features/Transfer/Sources/ViewModels/ConfirmRecipientViewModel.swift index b34adee7d..99f5ed05e 100644 --- a/ios/Features/Transfer/Sources/ViewModels/ConfirmRecipientViewModel.swift +++ b/ios/Features/Transfer/Sources/ViewModels/ConfirmRecipientViewModel.swift @@ -74,8 +74,7 @@ extension ConfirmRecipientViewModel { return switch model.type { case let .stake(_, stakeType): switch stakeType { - case .stake, .unstake, .redelegate, .withdraw: true - case .rewards: false + case .stake, .unstake, .redelegate, .withdraw, .rewards: true case .freeze, .unfreeze: true } case .account, diff --git a/ios/Features/Transfer/Sources/ViewModels/ConfirmTransferSceneViewModel.swift b/ios/Features/Transfer/Sources/ViewModels/ConfirmTransferSceneViewModel.swift index 7f7bf9393..8d43af313 100644 --- a/ios/Features/Transfer/Sources/ViewModels/ConfirmTransferSceneViewModel.swift +++ b/ios/Features/Transfer/Sources/ViewModels/ConfirmTransferSceneViewModel.swift @@ -174,7 +174,7 @@ extension ConfirmTransferSceneViewModel: ListSectionProvideable { if case .generic = transferData.type { return [.app, .sender, .network] } - return [.app, .sender, .network, .recipient, .memo, .details] + return [.app, .sender, .recipient, .network, .memo, .details] }() result.append(ListSection(type: .details, detailItems)) diff --git a/ios/Features/Transfer/Tests/ViewModels/ConfirmRecipientViewModelTests.swift b/ios/Features/Transfer/Tests/ViewModels/ConfirmRecipientViewModelTests.swift index 9cfe4a41d..064c2de4e 100644 --- a/ios/Features/Transfer/Tests/ViewModels/ConfirmRecipientViewModelTests.swift +++ b/ios/Features/Transfer/Tests/ViewModels/ConfirmRecipientViewModelTests.swift @@ -109,6 +109,18 @@ struct ConfirmRecipientViewModelTests { #expect(item.title == Localized.Stake.validator) } + @Test + func stakeRewards() { + let model = ConfirmRecipientViewModel( + model: .mock(type: .stake(.mock(), .rewards([.mock()]))), + addressName: nil, + addressLink: .mock(), + ) + + guard case let .recipient(item) = model.itemModel else { return } + #expect(item.title == Localized.Stake.validator) + } + @Test func stakeFreeze() { let model = ConfirmRecipientViewModel( diff --git a/ios/Features/Transfer/Tests/ViewModels/ConfirmTransferSceneViewModelTests.swift b/ios/Features/Transfer/Tests/ViewModels/ConfirmTransferSceneViewModelTests.swift index 536479dba..cbea3a499 100644 --- a/ios/Features/Transfer/Tests/ViewModels/ConfirmTransferSceneViewModelTests.swift +++ b/ios/Features/Transfer/Tests/ViewModels/ConfirmTransferSceneViewModelTests.swift @@ -312,7 +312,7 @@ struct ConfirmTransferSceneViewModelTests { #expect(sections[3].id == "error") #expect(sections[0].values == [.header]) - #expect(sections[1].values == [.app, .sender, .network, .recipient, .memo, .details]) + #expect(sections[1].values == [.app, .sender, .recipient, .network, .memo, .details]) #expect(sections[2].values == [.networkFee]) #expect(sections[3].values == [.error]) }