diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt index a665d64a53..2415ba615a 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt @@ -2,7 +2,7 @@ package com.tangem.feature.swap.domain import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.domain.Currency -import com.tangem.feature.swap.domain.models.domain.SwapApproveType +import com.tangem.feature.swap.domain.models.domain.PermissionOptions import com.tangem.feature.swap.domain.models.ui.* interface SwapInteractor { @@ -40,19 +40,10 @@ interface SwapInteractor { * Gives permission to swap, this starts scan card process * * @param networkId network in which selected token - * @param approveData tx data to give approve, it loaded from 1inch in findBestQuote if needed - * @param forTokenContractAddress token contract address for which needs permission - * @param fromToken which token will be swapping - * @param approveType unlimited or tx amount approve + * @param permissionOptions data to give permissions */ @Throws(IllegalStateException::class) - suspend fun givePermissionToSwap( - networkId: String, - approveData: RequestApproveStateData, - forTokenContractAddress: String, - fromToken: Currency, - approveType: SwapApproveType, - ): TxState + suspend fun givePermissionToSwap(networkId: String, permissionOptions: PermissionOptions): TxState /** * Find best quote for given tokens to swap diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index c95c7319f5..835ebdf273 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -5,6 +5,7 @@ import com.tangem.feature.swap.domain.converters.CryptoCurrencyConverter import com.tangem.feature.swap.domain.models.DataError import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.domain.Currency +import com.tangem.feature.swap.domain.models.domain.PermissionOptions import com.tangem.feature.swap.domain.models.domain.PreparedSwapConfigState import com.tangem.feature.swap.domain.models.domain.SwapApproveType import com.tangem.feature.swap.domain.models.toStringWithRightOffset @@ -107,29 +108,23 @@ internal class SwapInteractorImpl @Inject constructor( ?: loadedTokens.firstOrNull { it.token.id == id }?.token } - override suspend fun givePermissionToSwap( - networkId: String, - approveData: RequestApproveStateData, - forTokenContractAddress: String, - fromToken: Currency, - approveType: SwapApproveType, - ): TxState { - val dataToSign = if (approveType == SwapApproveType.UNLIMITED) { - repository.dataToApprove(networkId, getTokenAddress(fromToken)).data + override suspend fun givePermissionToSwap(networkId: String, permissionOptions: PermissionOptions): TxState { + val dataToSign = if (permissionOptions.approveType == SwapApproveType.UNLIMITED) { + repository.dataToApprove(networkId, getTokenAddress(permissionOptions.fromToken)).data } else { - approveData.approveModel.data + permissionOptions.approveData.approveModel.data } val result = transactionManager.sendApproveTransaction( networkId = networkId, - feeAmount = approveData.fee, - gasLimit = approveData.gasLimit, - destinationAddress = approveData.approveModel.toAddress, + feeAmount = permissionOptions.txFee.feeValue, + gasLimit = permissionOptions.txFee.gasLimit, + destinationAddress = permissionOptions.approveData.approveModel.toAddress, dataToSign = dataToSign, derivationPath = derivationPath, ) return when (result) { is SendTxResult.Success -> { - allowPermissionsHandler.addAddressToInProgress(forTokenContractAddress) + allowPermissionsHandler.addAddressToInProgress(permissionOptions.forTokenContractAddress) TxState.TxSent(txAddress = userWalletManager.getLastTransactionHash(networkId, derivationPath) ?: "") } SendTxResult.UserCancelledError -> TxState.UserCancelled @@ -414,7 +409,7 @@ internal class SwapInteractorImpl @Inject constructor( val isBalanceIncludeFeeEnough = isBalanceEnough(networkId, fromToken, amount, txFeeState.priorityFee.feeValue) val isFeeEnough = checkFeeIsEnough( - fee = txFeeState.priorityFee.feeValue, + fee = txFeeState.normalFee.feeValue, spendAmount = amount, networkId = networkId, fromToken = fromToken, @@ -527,12 +522,7 @@ internal class SwapInteractorImpl @Inject constructor( data = transactionData.data, derivationPath = derivationPath, ) - val feeFiat = getFormattedFiatFees(networkId, feeData.normalFee.fee.value) - val formattedFee = amountFormatter.formatBigDecimalAmountToUI( - amount = feeData.normalFee.fee.value, - decimals = transactionManager.getNativeTokenDecimals(networkId), - currency = userWalletManager.getNetworkCurrency(networkId), - ) + (feeFiat.firstOrNull() ?: "") + val feeState = proxyFeesToFeeState(networkId, feeData) val isFeeEnough = checkFeeIsEnough( fee = feeData.normalFee.fee.value, spendAmount = SwapAmount.zeroSwapAmount(), @@ -545,10 +535,8 @@ internal class SwapInteractorImpl @Inject constructor( amount = INFINITY_SYMBOL, walletAddress = getWalletAddress(networkId), spenderAddress = transactionData.toAddress, - fee = formattedFee, requestApproveData = RequestApproveStateData( - fee = feeData.normalFee.fee.value, - gasLimit = feeData.normalFee.gasLimit.toInt(), + fee = feeState, approveModel = transactionData, ), ), diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PermissionOptions.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PermissionOptions.kt new file mode 100644 index 0000000000..7c0f6812fb --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PermissionOptions.kt @@ -0,0 +1,21 @@ +package com.tangem.feature.swap.domain.models.domain + +import com.tangem.feature.swap.domain.models.ui.RequestApproveStateData +import com.tangem.feature.swap.domain.models.ui.TxFee + +/** + * Permission options + * + * @param approveData tx data to give approve, it loaded from 1inch in findBestQuote if needed + * @param forTokenContractAddress token contract address for which needs permission + * @param fromToken which token will be swapping + * @param approveType unlimited or tx amount approve + * @param txFee fee for tx + */ +data class PermissionOptions( + val approveData: RequestApproveStateData, + val forTokenContractAddress: String, + val fromToken: Currency, + val approveType: SwapApproveType, + val txFee: TxFee, +) \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt index 16820a3f9f..8e4258d548 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt @@ -40,7 +40,6 @@ sealed class PermissionDataState { val amount: String, val walletAddress: String, val spenderAddress: String, - val fee: String, val requestApproveData: RequestApproveStateData, ) : PermissionDataState() @@ -59,8 +58,7 @@ data class TokenSwapInfo( ) data class RequestApproveStateData( - val fee: BigDecimal, - val gasLimit: Int, + val fee: TxFeeState, val approveModel: ApproveModel, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapPermissionStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapPermissionStateHolder.kt index 8b6d4dd0c0..4192106336 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapPermissionStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapPermissionStateHolder.kt @@ -1,5 +1,6 @@ package com.tangem.feature.swap.models +import com.tangem.core.ui.extensions.TextReference import com.tangem.feature.swap.domain.models.domain.SwapApproveType import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -15,7 +16,7 @@ sealed class SwapPermissionState { val amount: String, val walletAddress: String, val spenderAddress: String, - val fee: String, + val fee: TextReference, val approveType: ApproveType, val approveItems: ImmutableList = ApproveType.values().toList().toImmutableList(), val approveButton: ApprovePermissionButton, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt index 966f4b9bb9..a7ea53771e 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt @@ -57,17 +57,21 @@ sealed class FeeState(open val tangemFee: Double) { data class Loaded( override val tangemFee: Double, - val state: SelectableItemsState?, + override val state: SelectableItemsState?, val onSelectItem: (Item) -> Unit, - ) : FeeState(tangemFee) + ) : FeeState(tangemFee), FeeSelectState object Loading : FeeState(0.0) data class NotEnoughFundsWarning( override val tangemFee: Double, - val state: SelectableItemsState?, + override val state: SelectableItemsState?, val onSelectItem: (Item) -> Unit, - ) : FeeState(tangemFee) + ) : FeeState(tangemFee), FeeSelectState +} + +sealed interface FeeSelectState { + val state: SelectableItemsState? } sealed interface TransactionCardType { diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 88cd6f81f6..00e8323623 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -161,6 +161,7 @@ internal class StateBuilder(val actions: UiActions) { permissionState = convertPermissionState( lastPermissionState = uiStateHolder.permissionState, permissionDataState = quoteModel.permissionState, + feeState = feeState, onGivePermissionClick = actions.onGivePermissionClick, onChangeApproveType = actions.onChangeApproveType, ), @@ -269,6 +270,14 @@ internal class StateBuilder(val actions: UiActions) { val newSelectedItem = item.copy( startText = TextReference.Res(R.string.send_network_fee_title), ) + val permissionState = uiState.permissionState + val newPermissionState = if (permissionState is SwapPermissionState.ReadyForRequest) { + permissionState.copy( + fee = newSelectedItem.endText, + ) + } else { + permissionState + } return when (val fee = uiState.fee) { is FeeState.Loaded -> { val newState = fee.state?.copy( @@ -277,6 +286,7 @@ internal class StateBuilder(val actions: UiActions) { ) uiState.copy( fee = fee.copy(state = newState), + permissionState = newPermissionState, ) } is FeeState.NotEnoughFundsWarning -> { @@ -286,6 +296,7 @@ internal class StateBuilder(val actions: UiActions) { ) uiState.copy( fee = fee.copy(state = newState), + permissionState = newPermissionState, ) } else -> uiState @@ -302,8 +313,14 @@ internal class StateBuilder(val actions: UiActions) { is FeeState.NotEnoughFundsWarning -> stateFee.state else -> null } + val permissionState = quoteModel.permissionState + val feeState = if (permissionState is PermissionDataState.PermissionReadyForRequest) { + permissionState.requestApproveData.fee + } else { + quoteModel.swapDataModel?.fee + } val selectFeeState = createSelectFeeState( - fee = quoteModel.swapDataModel?.fee, + fee = feeState, previousState = previousFeeState, onFeeSetup = onFeeSetup, ) @@ -407,6 +424,7 @@ internal class StateBuilder(val actions: UiActions) { private fun convertPermissionState( lastPermissionState: SwapPermissionState, permissionDataState: PermissionDataState, + feeState: FeeState, onGivePermissionClick: () -> Unit, onChangeApproveType: (ApproveType) -> Unit, ): SwapPermissionState { @@ -415,6 +433,10 @@ internal class StateBuilder(val actions: UiActions) { } else { ApproveType.UNLIMITED } + val fee = when (feeState) { + is FeeSelectState -> feeState.state?.selectedItem?.endText + else -> null + } return when (permissionDataState) { PermissionDataState.Empty -> SwapPermissionState.Empty PermissionDataState.PermissionFailed -> SwapPermissionState.Empty @@ -425,7 +447,7 @@ internal class StateBuilder(val actions: UiActions) { approveType = approveType, walletAddress = getShortAddressValue(permissionDataState.walletAddress), spenderAddress = getShortAddressValue(permissionDataState.spenderAddress), - fee = permissionDataState.fee, + fee = fee ?: TextReference.Str(""), approveButton = ApprovePermissionButton( enabled = true, onClick = onGivePermissionClick, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheetContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheetContent.kt index 7190919db7..1f87fc061f 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheetContent.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheetContent.kt @@ -13,6 +13,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.components.* import com.tangem.core.ui.components.atoms.Hand +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.swap.models.ApprovePermissionButton import com.tangem.feature.swap.models.ApproveType @@ -123,7 +125,7 @@ private fun ApprovalBottomSheetInfo(data: SwapPermissionState.ReadyForRequest) { ) SpacerH24() DividerBottomSheet() - FeeItem(fee = data.fee) + FeeItem(fee = data.fee.resolveReference()) SubtitleItem( subtitle = stringResource(id = R.string.swapping_permission_fee_footer), modifier = Modifier.fillMaxWidth(), @@ -303,7 +305,7 @@ private val previewData = SwapPermissionState.ReadyForRequest( amount = "∞", walletAddress = "", spenderAddress = "", - fee = "2,14$", + fee = TextReference.Str("2,14$"), approveType = ApproveType.UNLIMITED, approveButton = ApprovePermissionButton(true) {}, cancelButton = CancelPermissionButton(true), diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 2376e4c61e..e7a96cac0c 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -12,6 +12,7 @@ import com.tangem.feature.swap.analytics.SwapEvents import com.tangem.feature.swap.domain.BlockchainInteractor import com.tangem.feature.swap.domain.SwapInteractor import com.tangem.feature.swap.domain.models.domain.Currency +import com.tangem.feature.swap.domain.models.domain.PermissionOptions import com.tangem.feature.swap.domain.models.formatToUIRepresentation import com.tangem.feature.swap.domain.models.ui.* import com.tangem.feature.swap.models.SwapPermissionState @@ -276,17 +277,22 @@ internal class SwapViewModel @Inject constructor( runCatching(dispatchers.io) { swapInteractor.givePermissionToSwap( networkId = dataState.networkId, - approveData = requireNotNull(dataState.approveDataModel) { - Timber.e("dataState.approveDataModel might not be null") - }, - forTokenContractAddress = (dataState.fromCurrency as? Currency.NonNativeToken)?.contractAddress - ?: "", - fromToken = requireNotNull(dataState.fromCurrency) { - Timber.e("dataState.fromCurrency might not be null") - }, - approveType = requireNotNull(uiState.permissionState as? SwapPermissionState.ReadyForRequest) { - Timber.e("uiState.permissionState should be SwapPermissionState.ReadyForRequest") - }.approveType.toDomainApproveType(), + permissionOptions = PermissionOptions( + approveData = requireNotNull(dataState.approveDataModel) { + "dataState.approveDataModel might not be null" + }, + forTokenContractAddress = (dataState.fromCurrency as? Currency.NonNativeToken)?.contractAddress + ?: "", + fromToken = requireNotNull(dataState.fromCurrency) { + "dataState.fromCurrency might not be null" + }, + approveType = requireNotNull(uiState.permissionState as? SwapPermissionState.ReadyForRequest) { + "uiState.permissionState should be SwapPermissionState.ReadyForRequest" + }.approveType.toDomainApproveType(), + txFee = requireNotNull(dataState.selectedFee) { + "dataState.selectedFee shouldn't be null" + }, + ), ) } .onSuccess {