From 925ae57742d1ae581fe0f2367721a237c911b18e Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Dec 2023 11:32:15 +0300 Subject: [PATCH 1/5] Updated on 2026-08-14 --- .../tangem/feature/swap/SwapRepositoryImpl.kt | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt index 24fa9fb08f..c95e9b4ddf 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt @@ -5,10 +5,7 @@ import arrow.core.left import arrow.core.raise.catch import arrow.core.raise.either import arrow.core.right -import com.tangem.blockchain.common.Amount -import com.tangem.blockchain.common.Approver -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.Token +import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.Result import com.tangem.data.tokens.utils.CryptoCurrencyFactory import com.tangem.datasource.api.common.response.ApiResponse @@ -347,23 +344,27 @@ internal class SwapRepositoryImpl @Inject constructor( return (walletManager as? Approver)?.getApproveData( spenderAddress, - amount?.let { convertToAmount(it, currency, blockchain) }, + amount?.let { convertToAmount(it, currency) }, ) ?: error("Cannot cast to Approver") } - private fun convertToAmount(amount: BigDecimal, currency: CryptoCurrency, blockchain: Blockchain): Amount { - return when (currency) { - is CryptoCurrency.Token -> { - Amount(value = amount, blockchain = blockchain) - } - is CryptoCurrency.Coin -> { - Amount( - currencySymbol = currency.symbol, - value = amount, - decimals = currency.decimals, + private fun convertToAmount(amount: BigDecimal, currency: CryptoCurrency): Amount { + return Amount( + currencySymbol = currency.symbol, + value = amount, + decimals = currency.decimals, + type = if (currency is CryptoCurrency.Token) { + AmountType.Token( + Token( + symbol = currency.symbol, + contractAddress = currency.contractAddress, + decimals = currency.decimals, + ), ) - } - } + } else { + AmountType.Coin + }, + ) } private fun getOneInchApi(networkId: String): OneInchApi { From f1ce18c109f7194c69c60354bb0e057f2fdfc77b Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Dec 2023 11:00:44 +0200 Subject: [PATCH 2/5] Updated on 2026-08-14 --- .../feature/swap/models/SwapStateHolder.kt | 10 +++++-- .../tangem/feature/swap/ui/StateBuilder.kt | 26 ++++++++++--------- .../feature/swap/ui/SwapScreenContent.kt | 5 ++-- .../tangem/feature/swap/ui/TransactionCard.kt | 13 ++++------ 4 files changed, 29 insertions(+), 25 deletions(-) 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 00b174011d..83d86eee5b 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 @@ -1,7 +1,9 @@ package com.tangem.feature.swap.models import androidx.annotation.DrawableRes +import androidx.annotation.StringRes import androidx.compose.ui.text.input.TextFieldValue +import com.tangem.core.ui.R import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.notifications.NotificationConfig import com.tangem.core.ui.components.states.Item @@ -99,13 +101,17 @@ sealed interface FeeSelectState { sealed interface TransactionCardType { - data class SendCard( + val headerResId: Int + + data class Inputtable( val onAmountChanged: ((String) -> Unit), val onFocusChanged: ((Boolean) -> Unit), + @StringRes override val headerResId: Int = R.string.exchange_send_view_header, ) : TransactionCardType - data class ReceiveCard( + data class ReadOnly( val highPriceImpact: String? = null, + @StringRes override val headerResId: Int = R.string.exchange_receive_view_header, ) : 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 cbc20fe451..5452767ef8 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 @@ -50,7 +50,7 @@ internal class StateBuilder( return SwapStateHolder( blockchainId = networkInfo.blockchainId, sendCardData = SwapCardState.SwapCardData( - type = TransactionCardType.SendCard(actions.onAmountChanged, actions.onAmountSelected), + type = TransactionCardType.Inputtable(actions.onAmountChanged, actions.onAmountSelected), amountEquivalent = null, amountTextFieldValue = null, token = null, @@ -64,7 +64,7 @@ internal class StateBuilder( isBalanceHidden = true, ), receiveCardData = SwapCardState.SwapCardData( - type = TransactionCardType.ReceiveCard(), + type = TransactionCardType.ReadOnly(), amountEquivalent = null, tokenIconUrl = "", tokenCurrency = "", @@ -98,7 +98,9 @@ internal class StateBuilder( if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder return uiStateHolder.copy( sendCardData = SwapCardState.SwapCardData( - type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard), + type = TransactionCardType.ReadOnly( + headerResId = R.string.exchange_send_view_header + ), amountTextFieldValue = TextFieldValue( text = "0", ), @@ -114,7 +116,7 @@ internal class StateBuilder( isBalanceHidden = isBalanceHiddenProvider(), ), receiveCardData = SwapCardState.Empty( - type = TransactionCardType.ReceiveCard(), + type = TransactionCardType.ReadOnly(), amountEquivalent = "0 ${appCurrencyProvider.invoke().symbol}", amountTextFieldValue = TextFieldValue( text = "0", @@ -156,7 +158,7 @@ internal class StateBuilder( if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder return uiStateHolder.copy( sendCardData = SwapCardState.SwapCardData( - type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard), + type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.Inputtable), amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue, amountEquivalent = null, token = uiStateHolder.sendCardData.token, @@ -170,7 +172,7 @@ internal class StateBuilder( isBalanceHidden = isBalanceHiddenProvider(), ), receiveCardData = SwapCardState.SwapCardData( - type = TransactionCardType.ReceiveCard(), + type = TransactionCardType.ReadOnly(), amountTextFieldValue = null, amountEquivalent = null, token = uiStateHolder.receiveCardData.token, @@ -220,7 +222,7 @@ internal class StateBuilder( val toCurrencyStatus = quoteModel.toTokenInfo.cryptoCurrencyStatus return uiStateHolder.copy( sendCardData = SwapCardState.SwapCardData( - type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard), + type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.Inputtable), amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue, amountEquivalent = getFormattedFiatAmount(quoteModel.fromTokenInfo.amountFiat), token = fromCurrencyStatus, @@ -234,7 +236,7 @@ internal class StateBuilder( isBalanceHidden = isBalanceHiddenProvider(), ), receiveCardData = SwapCardState.SwapCardData( - type = TransactionCardType.ReceiveCard(), + type = TransactionCardType.ReadOnly(), amountTextFieldValue = TextFieldValue(quoteModel.toTokenInfo.tokenAmount.formatToUIRepresentation()), amountEquivalent = getFormattedFiatAmount(quoteModel.toTokenInfo.amountFiat), token = toCurrencyStatus, @@ -419,7 +421,7 @@ internal class StateBuilder( ) val receiveCardData = toToken?.let { SwapCardState.SwapCardData( - type = TransactionCardType.ReceiveCard(), + type = TransactionCardType.ReadOnly(), amountTextFieldValue = TextFieldValue( text = "0", ), @@ -435,7 +437,7 @@ internal class StateBuilder( isBalanceHidden = isBalanceHiddenProvider(), ) } ?: SwapCardState.Empty( - type = TransactionCardType.ReceiveCard(), + type = TransactionCardType.ReadOnly(), amountEquivalent = "0 ${appCurrencyProvider.invoke().symbol}", amountTextFieldValue = TextFieldValue( text = "0", @@ -533,7 +535,7 @@ internal class StateBuilder( if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder return uiStateHolder.copy( sendCardData = SwapCardState.SwapCardData( - type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard), + type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.Inputtable), amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue, amountEquivalent = emptyAmountState.zeroAmountEquivalent, token = uiStateHolder.sendCardData.token, @@ -547,7 +549,7 @@ internal class StateBuilder( isBalanceHidden = isBalanceHiddenProvider(), ), receiveCardData = SwapCardState.SwapCardData( - type = TransactionCardType.ReceiveCard(), + type = TransactionCardType.ReadOnly(), amountTextFieldValue = TextFieldValue("0"), amountEquivalent = emptyAmountState.zeroAmountEquivalent, token = uiStateHolder.receiveCardData.token, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt index 1e0b3f5944..b211130172 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt @@ -1,6 +1,5 @@ package com.tangem.feature.swap.ui -import androidx.compose.animation.* import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape @@ -429,7 +428,7 @@ private fun MainButton(state: SwapStateHolder, onPermissionWarningClick: () -> U // region preview private val sendCard = SwapCardState.SwapCardData( - type = TransactionCardType.SendCard({}) {}, + type = TransactionCardType.Inputtable({}, {}), amountTextFieldValue = TextFieldValue(), amountEquivalent = "1 000 000", tokenIconUrl = "", @@ -444,7 +443,7 @@ private val sendCard = SwapCardState.SwapCardData( ) private val receiveCard = SwapCardState.SwapCardData( - type = TransactionCardType.ReceiveCard(), + type = TransactionCardType.ReadOnly(), amountTextFieldValue = TextFieldValue(), amountEquivalent = "1 000 000", tokenIconUrl = "", diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt index 5b16375022..0aec67858b 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt @@ -182,10 +182,7 @@ private fun Header(type: TransactionCardType, balance: String, modifier: Modifie horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - val title = when (type) { - is TransactionCardType.ReceiveCard -> R.string.exchange_receive_view_header - is TransactionCardType.SendCard -> R.string.exchange_send_view_header - } + val title = type.headerResId Text( text = stringResource(id = title), color = TangemTheme.colors.text.tertiary, @@ -245,7 +242,7 @@ private fun Content( ) { val sumTextModifier = Modifier.defaultMinSize(minHeight = TangemTheme.dimens.size32) when (type) { - is TransactionCardType.ReceiveCard -> { + is TransactionCardType.ReadOnly -> { if (textFieldValue != null) { ResizableText( text = textFieldValue.text, @@ -263,7 +260,7 @@ private fun Content( ) } } - is TransactionCardType.SendCard -> { + is TransactionCardType.Inputtable -> { AutoSizeTextField( modifier = sumTextModifier, textFieldValue = textFieldValue ?: TextFieldValue(), @@ -276,7 +273,7 @@ private fun Content( SpacerH8() if (amountEquivalent != null) { - if (type is TransactionCardType.ReceiveCard && priceImpact !is PriceImpact.Empty) { + if (type is TransactionCardType.ReadOnly && priceImpact !is PriceImpact.Empty) { Row { Text( text = makePriceImpactBalanceWarning(amountEquivalent, priceImpact.getIntPercentValue()), @@ -485,7 +482,7 @@ private fun Preview_SwapMainCard_InDarkTheme() { @Composable private fun TransactionCardPreview() { TransactionCard( - type = TransactionCardType.SendCard({}) {}, + type = TransactionCardType.Inputtable({}, {}), amountEquivalent = "1 000 000", tokenIconUrl = "", tokenCurrency = "DAI", From a4beb2cafcf20e2978ddf65c9f684fb21f66e84e Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Dec 2023 19:48:11 +0300 Subject: [PATCH 3/5] Updated on 2026-08-14 --- gradle/dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 6a3614624a..237bd3e4a9 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -88,7 +88,7 @@ spr-client = "3.6.2" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_5.4-419" +tangemBlockchainSdk = "release-app_5.4-423" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_5.4-315" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From bd62089c128dff98b73fb7b733b4c39da3ead983 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Dec 2023 19:58:56 +0300 Subject: [PATCH 4/5] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- .../auth/DefaultExpressAuthProvider.kt | 2 +- .../network/auth/DefaultOneInchProvider.kt | 13 -- .../tangem/tap/network/auth/di/AuthModule.kt | 10 - .../api/express/TangemExpressApi.kt | 1 + .../models/response/ExchangeDataResponse.kt | 21 +- .../datasource/api/oneinch/OneInchApi.kt | 205 ------------------ .../api/oneinch/OneInchApiFactory.kt | 14 -- .../api/oneinch/OneInchErrorsHandler.kt | 35 --- .../oneinch/errors/OneIncResponseException.kt | 5 - .../api/oneinch/models/AllowanceResponse.kt | 7 - .../oneinch/models/ApproveCalldataResponse.kt | 18 -- .../oneinch/models/ApproveSpenderResponse.kt | 12 - .../api/oneinch/models/PathViewDto.kt | 13 -- .../api/oneinch/models/ProtocolsResponse.kt | 27 --- .../api/oneinch/models/QuoteResponse.kt | 14 -- .../api/oneinch/models/StatusResponse.kt | 8 - .../api/oneinch/models/SwapErrorDto.kt | 42 ---- .../api/oneinch/models/SwapResponse.kt | 10 - .../api/oneinch/models/TokenOneInchDto.kt | 20 -- .../api/oneinch/models/TokensResponse.kt | 12 - .../api/oneinch/models/TransactionDto.kt | 23 -- .../datasource/config/ConfigManagerImpl.kt | 4 +- .../tangem/datasource/config/models/Config.kt | 4 +- .../datasource/config/models/ExpressModel.kt | 12 + .../datasource/config/models/JsonModels.kt | 9 +- .../crypto/DataSignatureVerifier.kt | 6 + .../crypto/Sha256SignatureVerifier.kt | 17 ++ .../tangem/datasource/di/OneInchApisModule.kt | 96 -------- .../tangem/datasource/di/SecurityModule.kt | 21 ++ features/swap/data/build.gradle.kts | 3 + ...sitoryImpl.kt => DefaultSwapRepository.kt} | 54 +++-- .../swap/converters/ExpressDataConverter.kt | 28 ++- .../tangem/feature/swap/di/SwapDataModule.kt | 19 +- .../feature/swap/domain/api/SwapRepository.kt | 13 -- .../feature/swap/domain/models/DataError.kt | 4 + .../swap/domain/models/ui/SwapState.kt | 1 - .../feature/swap/domain/SwapInteractorImpl.kt | 6 - .../tangem/feature/swap/ui/StateBuilder.kt | 2 +- 39 files changed, 149 insertions(+), 664 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/network/auth/DefaultOneInchProvider.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApi.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApiFactory.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchErrorsHandler.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/errors/OneIncResponseException.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/AllowanceResponse.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveCalldataResponse.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveSpenderResponse.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/PathViewDto.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ProtocolsResponse.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/QuoteResponse.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/StatusResponse.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapErrorDto.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapResponse.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokenOneInchDto.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokensResponse.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TransactionDto.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/config/models/ExpressModel.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/crypto/DataSignatureVerifier.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/crypto/Sha256SignatureVerifier.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/di/OneInchApisModule.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/di/SecurityModule.kt rename features/swap/data/src/main/java/com/tangem/feature/swap/{SwapRepositoryImpl.kt => DefaultSwapRepository.kt} (89%) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 6ef8ce45d1..0be5650f8f 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 6ef8ce45d183905b5752e2d33c1d8bf2f4bcace6 +Subproject commit 0be5650f8fbcdff22c23fe2e2c7d754c4275a6f6 diff --git a/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt b/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt index 70d580f3c7..6cd26d788e 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt @@ -15,7 +15,7 @@ internal class DefaultExpressAuthProvider( private var uuid = AtomicReference(UUID.randomUUID()) override fun getApiKey(): String { - return configManager.config.tangemExpressApiKey + return configManager.config.express?.apiKey ?: "" } override fun getUserId(): String { diff --git a/app/src/main/java/com/tangem/tap/network/auth/DefaultOneInchProvider.kt b/app/src/main/java/com/tangem/tap/network/auth/DefaultOneInchProvider.kt deleted file mode 100644 index ade4f48a0f..0000000000 --- a/app/src/main/java/com/tangem/tap/network/auth/DefaultOneInchProvider.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.tap.network.auth - -import com.tangem.datasource.config.ConfigManager -import com.tangem.lib.auth.AuthBearerProvider - -internal class DefaultOneInchProvider( - private val configManager: ConfigManager, -) : AuthBearerProvider { - - override fun getApiKey(): String { - return configManager.config.oneInchApiKey - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt index d59b3f4792..fa9aa920a1 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt @@ -2,12 +2,10 @@ package com.tangem.tap.network.auth.di import com.tangem.datasource.config.ConfigManager import com.tangem.datasource.local.userwallet.UserWalletsStore -import com.tangem.lib.auth.AuthBearerProvider import com.tangem.lib.auth.AuthProvider import com.tangem.lib.auth.ExpressAuthProvider import com.tangem.tap.network.auth.DefaultAuthProvider import com.tangem.tap.network.auth.DefaultExpressAuthProvider -import com.tangem.tap.network.auth.DefaultOneInchProvider import com.tangem.tap.proxy.AppStateHolder import dagger.Module import dagger.Provides @@ -36,12 +34,4 @@ class AuthModule { configManager = configManager, ) } - - @Provides - @Singleton - fun provideOneInchAuthProvider(configManager: ConfigManager): AuthBearerProvider { - return DefaultOneInchProvider( - configManager = configManager, - ) - } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt index b78d485fa6..61c2a6c25a 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt @@ -49,6 +49,7 @@ interface TangemExpressApi { @Query("providerId") providerId: String, @Query("rateType") rateType: String, @Query("toAddress") toAddress: String, + @Query("requestId") requestId: String, ): ApiResponse @GET("exchange-status") diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt index b44fa2a019..40c3483f16 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt @@ -3,6 +3,10 @@ package com.tangem.datasource.api.express.models.response import com.squareup.moshi.Json import java.math.BigDecimal +data class ExchangeDataResponseWithTxDetails( + val dataResponse: ExchangeDataResponse, + val txDetails: TxDetails, +) data class ExchangeDataResponse( @Json(name = "fromAmount") val fromAmount: String, @@ -16,12 +20,23 @@ data class ExchangeDataResponse( @Json(name = "toDecimals") val toDecimals: Int, - @Json(name = "txType") - val txType: TxType, - @Json(name = "txId") val txId: String, // inner tangem-express transaction id + @Json(name = "txDetailsJson") + val txDetailsJson: String, + + @Json(name = "signature") + val signature: String, +) + +data class TxDetails( + @Json(name = "requestId") + val requestId: String, + + @Json(name = "txType") + val txType: TxType, + @Json(name = "txFrom") val txFrom: String?, // account for debiting tokens (same as toAddress) if DEX, null if CEX diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApi.kt deleted file mode 100644 index cf950a0f66..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApi.kt +++ /dev/null @@ -1,205 +0,0 @@ -package com.tangem.datasource.api.oneinch - -import com.tangem.datasource.api.oneinch.models.AllowanceResponse -import com.tangem.datasource.api.oneinch.models.ApproveCalldataResponse -import com.tangem.datasource.api.oneinch.models.ApproveSpenderResponse -import com.tangem.datasource.api.oneinch.models.ProtocolsResponse -import com.tangem.datasource.api.oneinch.models.QuoteResponse -import com.tangem.datasource.api.oneinch.models.StatusResponse -import com.tangem.datasource.api.oneinch.models.SwapResponse -import com.tangem.datasource.api.oneinch.models.TokensResponse -import retrofit2.Response -import retrofit2.http.GET -import retrofit2.http.Query - -interface OneInchApi { - - /** - * Healthcheck return 200 if service is available - * - * @return [StatusResponse] - */ - @GET("healthcheck") - suspend fun healthcheck(): StatusResponse - - //region Approve - /** - * Address of the 1inch router that must be trusted to spend funds for the exchange - * - * @return [ApproveSpenderResponse] - */ - @GET("approve/spender") - suspend fun approveSpender(): ApproveSpenderResponse - - /** - * Generate data for calling the contract in order to allow the 1inch router to spend funds - * - * @param tokenAddress Token address you want to exchange - * @param amount The number of tokens that the 1inch router is allowed to spend. - * If not specified, it will be allowed to spend an infinite amount of tokens. - * - * @return [ApproveCalldataResponse] Transaction body to allow the exchange with the 1inch router - */ - @GET("approve/transaction") - suspend fun approveTransaction( - @Query("tokenAddress") tokenAddress: String, - @Query("amount") amount: String? = null, - ): ApproveCalldataResponse - - /** - * Get the number of tokens that the 1inch router is allowed to spend - * - * @param tokenAddress Token address you want to exchange - * @param walletAddress Wallet address for which you want to check - * - * @return [AllowanceResponse] - */ - @GET("approve/allowance") - suspend fun approveAllowance( - @Query("tokenAddress") tokenAddress: String, - @Query("walletAddress") walletAddress: String, - ): Response - //endregion Approve - - //region Info - /** - * List of tokens that are available for swap in the 1inch Aggregation protocol - * - * @return [TokensResponse] - */ - @GET("tokens") - suspend fun tokensAvailable(): TokensResponse - - /** - * List of liquidity sources that are available for routing in the 1inch Aggregation protocol - * - * @return - */ - @GET("liquidity-sources") - suspend fun liquiditySources(): ProtocolsResponse - //endregion Info - - //region Swap - /** - * Find the best quote to exchange via 1inch router - * - * @param fromTokenAddress Example : 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE - * @param toTokenAddress Example : 0x111111111117dc0aa78b770fa6a738034120c302 - * @param amount amount of a token to sell, set in minimal divisible units e.g.: - * 1.00 DAI set as 1000000000000000000 - * 51.03 USDC set as 51030000 - * - * @param protocols default: all - * @param fee this percentage of fromTokenAddress token amount will be sent to referrerAddress, - * the rest will be used as input for a swap - * Min: 0; max: 3; Max: 0; max: 3; default: 0; !should be the same for quote and swap! - * - * @param gasLimit maximum amount of gas for a swap; - * @param connectorTokens token-connectors can be specified via this parameter. - * The more is set — the longer route estimation will take. - * If not set, default token-connectors will be usedmax: 5; !should be the same for quote and swap! - * - * @param complexityLevel maximum number of token-connectors to be used in a transaction. - * The more is used — the longer route estimation will take - * min: 0; max: 3; default: 2; !should be the same for quote and swap! - * - * @param mainRouteParts default: 10; max: 50 !should be the same for quote and swap! - * @param parts limit maximum number of parts each main route parts can be split into; - * should be the same for a quote and swap - * default: 20; max: 100 - * - * @param gasPrice 1inch takes in account gas expenses to determine exchange route. - * It is important to use the same gas price on the quote and swap methods. - * Gas price set in wei: 12.5 GWEI set as 12500000000 - * default: fast from network - * - * @return [QuoteResponse] - */ - @GET("quote") - suspend fun quote( - @Query("src") fromTokenAddress: String, - @Query("dst") toTokenAddress: String, - @Query("amount") amount: String, - @Query("protocols") protocols: String? = null, - @Query("fee") fee: String? = null, - @Query("gasLimit") gasLimit: String? = null, - @Query("connectorTokens") connectorTokens: String? = null, - @Query("complexityLevel") complexityLevel: String? = null, - @Query("mainRouteParts") mainRouteParts: String? = null, - @Query("parts") parts: String? = null, - @Query("gasPrice") gasPrice: String? = null, - @Query("includeTokensInfo") includeTokensInfo: Boolean = true, - ): Response - - /** - * Generate data for calling the 1inch router for exchange - * - * @param fromTokenAddress Example : 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE - * @param toTokenAddress Example : 0x111111111117dc0aa78b770fa6a738034120c302 - * @param amount amount of a token to sell, set in minimal divisible units e.g.: - * 1.00 DAI set as 1000000000000000000 - * 51.03 USDC set as 51030000 - * - * @param fromAddress The address that calls the 1inch contract - * @param slippage limit of price slippage you are willing to accept in percentage, may be set with decimals. - * &slippage=0.5 means 0.5% slippage is acceptable. Low values increase chances that transaction will fail, - * high values increase chances of front running. min: 0; max: 50; - * - * @param protocols default: all - * @param destinationAddress Receiver of destination currency. default: fromAddress - * @param fee this percentage of fromTokenAddress token amount will be sent to referrerAddress, - * the rest will be used as input for a swap - * Min: 0; max: 3; Max: 0; max: 3; default: 0; !should be the same for quote and swap! - * - * @param permit https://eips.ethereum.org/EIPS/eip-2612 - * @param compatibilityMode Allows to build calldata without optimized routers - * @param burnChi If true, CHI will be burned from fromAddress to compensate gas. - * Check CHI balance and allowance before turning that on. CHI should be approved for the spender address - * - * @param connectorTokens token-connectors can be specified via this parameter. - * The more is set — the longer route estimation will take. - * If not set, default token-connectors will be usedmax: 5; !should be the same for quote and swap! - * - * @param complexityLevel maximum number of token-connectors to be used in a transaction. - * The more is used — the longer route estimation will take - * min: 0; max: 3; default: 2; !should be the same for quote and swap! - * - * @param mainRouteParts default: 10; max: 50 !should be the same for quote and swap! - * @param parts limit maximum number of parts each main route parts can be split into; - * should be the same for a quote and swap - * default: 20; max: 100 - * - * @param gasLimit maximum amount of gas for a swap; - * @param gasPrice 1inch takes in account gas expenses to determine exchange route. - * It is important to use the same gas price on the quote and swap methods. - * Gas price set in wei: 12.5 GWEI set as 12500000000 - * default: fast from network - * - * @return [SwapResponse] - */ - @GET("swap") - suspend fun swap( - @Query("src") fromTokenAddress: String, - @Query("dst") toTokenAddress: String, - @Query("amount") amount: String, - @Query("from") fromAddress: String, - @Query("slippage") slippage: Int, - @Query("protocols") protocols: String? = null, - @Query("receiver") destinationAddress: String? = null, - @Query("referrer") referrerAddress: String? = null, - @Query("fee") fee: String? = null, - @Query("disableEstimate") disableEstimate: Boolean? = null, - @Query("permit") permit: String? = null, - @Query("compatibility") compatibilityMode: Boolean? = null, - @Query("burnChi") burnChi: Boolean? = null, - @Query("allowPartialFill") allowPartialFill: Boolean? = null, - @Query("parts") parts: String? = null, - @Query("mainRouteParts") mainRouteParts: String? = null, - @Query("connectorTokens") connectorTokens: String? = null, - @Query("complexityLevel") complexityLevel: String? = null, - @Query("gasLimit") gasLimit: String? = null, - @Query("gasPrice") gasPrice: String? = null, - @Query("includeTokensInfo") includeTokensInfo: Boolean = true, - ): Response - //endregion Swap -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApiFactory.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApiFactory.kt deleted file mode 100644 index da21f86558..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApiFactory.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.datasource.api.oneinch - -class OneInchApiFactory { - - private val oneInchApiMap = mutableMapOf() - - fun putApi(networkId: String, api: OneInchApi) { - oneInchApiMap[networkId] = api - } - - fun getApi(networkId: String): OneInchApi { - return oneInchApiMap[networkId] ?: error("no api found for networkId $networkId") - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchErrorsHandler.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchErrorsHandler.kt deleted file mode 100644 index 4fdc784ecb..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchErrorsHandler.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.tangem.datasource.api.oneinch - -import com.squareup.moshi.Moshi -import com.tangem.datasource.api.oneinch.errors.OneIncResponseException -import com.tangem.datasource.api.oneinch.models.SwapErrorDto -import com.tangem.datasource.di.NetworkMoshi -import retrofit2.HttpException -import retrofit2.Response -import javax.inject.Inject - -class OneInchErrorsHandler @Inject constructor(@NetworkMoshi moshi: Moshi) { - - private val errorMoshiAdapter = moshi.adapter(SwapErrorDto::class.java) - - @Throws(OneIncResponseException::class) - fun handleOneInchResponse(response: Response): T { - return if (response.isSuccessful) { - response.body() ?: error("response body is null") - } else { - when (response.code()) { - HTTP_CODE_400 -> { - val swapErrorDto = errorMoshiAdapter.fromJson(response.errorBody()?.string() ?: "") - throw OneIncResponseException(swapErrorDto ?: throw HttpException(response)) - } - else -> { - throw HttpException(response) - } - } - } - } - - companion object { - private const val HTTP_CODE_400 = 400 - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/errors/OneIncResponseException.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/errors/OneIncResponseException.kt deleted file mode 100644 index 94c94f6e32..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/errors/OneIncResponseException.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.datasource.api.oneinch.errors - -import com.tangem.datasource.api.oneinch.models.SwapErrorDto - -class OneIncResponseException(val data: SwapErrorDto) : Exception() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/AllowanceResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/AllowanceResponse.kt deleted file mode 100644 index 16956f907e..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/AllowanceResponse.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -data class AllowanceResponse( - @Json(name = "allowance") val allowance: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveCalldataResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveCalldataResponse.kt deleted file mode 100644 index f57fab94fd..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveCalldataResponse.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Approve calldata response - * - * @property data The encoded data to call the approve method on the swapped token contract - * @property gasPrice Gas price for fast transaction processing - * @property toAddress Token address that will be allowed to exchange through 1inch router - * @property value Native token value in WEI (for approve is always 0) - */ -data class ApproveCalldataResponse( - @Json(name = "data") val data: String, - @Json(name = "gasPrice") val gasPrice: String, - @Json(name = "to") val toAddress: String, - @Json(name = "value") val value: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveSpenderResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveSpenderResponse.kt deleted file mode 100644 index 0ee9d5b2ac..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveSpenderResponse.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Approve spender response - * - * @property address Address of the 1inch router that must be trusted to spend funds for the exchange - */ -data class ApproveSpenderResponse( - @Json(name = "address") val address: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/PathViewDto.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/PathViewDto.kt deleted file mode 100644 index 03c23155ff..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/PathViewDto.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Path view dto - */ -data class PathViewDto( - @Json(name = "name") val name: String, - @Json(name = "part") val part: Int, - @Json(name = "fromTokenAddress") val fromTokenAddress: String, - @Json(name = "toTokenAddress") val toTokenAddress: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ProtocolsResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ProtocolsResponse.kt deleted file mode 100644 index b083cd1ce8..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ProtocolsResponse.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Protocols response - * - * @property protocols List of protocols that are available for routing in the 1inch Aggregation protocol - */ -data class ProtocolsResponse( - @Json(name = "protocols") val protocols: List, -) - -/** - * Protocol image - * - * @property id Protocol id - * @property title Protocol title - * @property image Protocol logo image - * @property imageColor Protocol logo image in color - */ -data class ProtocolImageDto( - @Json(name = "id") val id: String, - @Json(name = "title") val title: String, - @Json(name = "img") val image: String, - @Json(name = "img_color") val imageColor: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/QuoteResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/QuoteResponse.kt deleted file mode 100644 index 692f036f24..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/QuoteResponse.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Quote response - * - * @property toToken Destination token info - * @property toTokenAmount Expected amount of destination token - */ -data class QuoteResponse( - @Json(name = "toToken") val toToken: TokenOneInchDto, - @Json(name = "toAmount") val toTokenAmount: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/StatusResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/StatusResponse.kt deleted file mode 100644 index 576851a3b5..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/StatusResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -data class StatusResponse( - @Json(name = "status") val status: String, - @Json(name = "provider") val provider: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapErrorDto.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapErrorDto.kt deleted file mode 100644 index fe342de231..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapErrorDto.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Swap error dto - * - * One of the following errors: - * - * -Insufficient liquidity - * -Cannot estimate - * -You may not have enough ETH balance for gas fee - * -FromTokenAddress cannot be equals to toTokenAddress - * -Cannot estimate. Don't forget about miner fee. Try to leave the buffer of ETH for gas - * -Not enough balance - * -Not enough allowance - * - * @property statusCode HTTP code - * @property error Error code description - * @property description Error description (one of the following) - * @property requestId Request id - * @property meta Meta information - * @constructor Create empty Swap error dto - */ -data class SwapErrorDto( - @Json(name = "statusCode") val statusCode: Int, - @Json(name = "error") val error: String, - @Json(name = "description") val description: String, - @Json(name = "requestId") val requestId: String, - @Json(name = "meta") val meta: List, -) - -/** - * Nest error meta - * - * @property type Type of field - * @property value Value of field - */ -data class NestErrorMeta( - @Json(name = "type") val type: String, - @Json(name = "value") val value: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapResponse.kt deleted file mode 100644 index bc1f668360..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapResponse.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -data class SwapResponse( - @Json(name = "fromToken") val fromToken: TokenOneInchDto, - @Json(name = "toToken") val toToken: TokenOneInchDto, - @Json(name = "toAmount") val toTokenAmount: String, - @Json(name = "tx") val transaction: TransactionDto, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokenOneInchDto.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokenOneInchDto.kt deleted file mode 100644 index 0c06f15d84..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokenOneInchDto.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Token one inch - * - * @property symbol token symbol - * @property name token name - * @property address token address - * @property decimals token decimals - * @property logoURI token logo image url - */ -data class TokenOneInchDto( - @Json(name = "symbol") val symbol: String, - @Json(name = "name") val name: String, - @Json(name = "address") val address: String, - @Json(name = "decimals") val decimals: Int, - @Json(name = "logoURI") val logoURI: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokensResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokensResponse.kt deleted file mode 100644 index ca1b369949..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokensResponse.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Tokens response - * - * @property tokens List of supported tokens - */ -data class TokensResponse( - @Json(name = "tokens") val tokens: Map, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TransactionDto.kt b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TransactionDto.kt deleted file mode 100644 index a32e827601..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TransactionDto.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.datasource.api.oneinch.models - -import com.squareup.moshi.Json - -/** - * Transaction dto - * - * @property fromAddress transactions will be sent from this address - * @property toAddress transactions will be sent to our(1inch) contract address - * @property data The encoded data to call the approve method on the swapped token contract - * @property value Native token value in WEI (for approve is always 0) - * @property gasPrice maximum amount of gas for a swap default: 11500000; max: 11500000 - * @property gas estimated amount of the gas limit, increase this value by 25% - * @constructor Create empty Transaction dto - */ -data class TransactionDto( - @Json(name = "from") val fromAddress: String, - @Json(name = "to") val toAddress: String, - @Json(name = "data") val data: String, - @Json(name = "value") val value: String, - @Json(name = "gasPrice") val gasPrice: String, - @Json(name = "gas") val gas: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt index 3771cc18a6..4ac0edf918 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt @@ -103,11 +103,9 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager { amplitudeApiKey = configValues.amplitudeApiKey, shopify = configValues.shopifyShop, sprinklr = configValues.sprinklr, - swapReferrerAccount = configValues.swapReferrerAccount, walletConnectProjectId = configValues.walletConnectProjectId, tangemComAuthorization = configValues.tangemComAuthorization, - tangemExpressApiKey = configValues.tangemExpressApiKey, - oneInchApiKey = configValues.oneInchApiKey, + express = configValues.express, ) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt index 5ddc1a7187..8490f44237 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt @@ -16,9 +16,7 @@ data class Config( val isCreatingTwinCardsAllowed: Boolean = false, val shopify: ShopifyShop? = null, val sprinklr: SprinklrConfig? = null, - val swapReferrerAccount: SwapReferrerAccount? = null, val walletConnectProjectId: String = "", val tangemComAuthorization: String? = null, - val tangemExpressApiKey: String = "", - val oneInchApiKey: String = "", + val express: ExpressModel? = null, ) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/ExpressModel.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/ExpressModel.kt new file mode 100644 index 0000000000..19f97e4d8e --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/ExpressModel.kt @@ -0,0 +1,12 @@ +package com.tangem.datasource.config.models + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class ExpressModel( + @Json(name = "apiKey") + val apiKey: String, + @Json(name = "signVerifierPublicKey") + val signVerifierPublicKey: String, +) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt index d63f6527da..e953742589 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt @@ -35,14 +35,12 @@ class ConfigValueModel( val sprinklr: SprinklrConfig?, val tronGridApiKey: String, val amplitudeApiKey: String, - val swapReferrerAccount: SwapReferrerAccount?, val kaspaSecondaryApiUrl: String, val walletConnectProjectId: String, val tangemComAuthorization: String?, val chiaFireAcademyApiKey: String?, val chiaTangemApiKey: String?, - val tangemExpressApiKey: String, - val oneInchApiKey: String, + val express: ExpressModel?, ) @JsonClass(generateAdapter = true) @@ -84,11 +82,6 @@ data class AppsFlyer( val appsFlyerAppID: String, ) -data class SwapReferrerAccount( - val address: String, - val fee: String, -) - class ConfigModel( val features: FeatureModel?, val configValues: ConfigValueModel?, diff --git a/core/datasource/src/main/java/com/tangem/datasource/crypto/DataSignatureVerifier.kt b/core/datasource/src/main/java/com/tangem/datasource/crypto/DataSignatureVerifier.kt new file mode 100644 index 0000000000..1c3a8b68df --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/crypto/DataSignatureVerifier.kt @@ -0,0 +1,6 @@ +package com.tangem.datasource.crypto + +interface DataSignatureVerifier { + + fun verifySignature(signature: String, data: String): Boolean +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/crypto/Sha256SignatureVerifier.kt b/core/datasource/src/main/java/com/tangem/datasource/crypto/Sha256SignatureVerifier.kt new file mode 100644 index 0000000000..dc2c197c50 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/crypto/Sha256SignatureVerifier.kt @@ -0,0 +1,17 @@ +package com.tangem.datasource.crypto + +import com.tangem.common.extensions.hexToBytes +import com.tangem.crypto.CryptoUtils +import com.tangem.datasource.config.ConfigManager + +internal class Sha256SignatureVerifier(private val configManager: ConfigManager) : DataSignatureVerifier { + + override fun verifySignature(signature: String, data: String): Boolean { + val pubKey = configManager.config.express?.signVerifierPublicKey ?: return false + return CryptoUtils.verify( + publicKey = pubKey.hexToBytes().takeLast(n = 65).toByteArray(), + message = data.toByteArray(), + signature = signature.hexToBytes(), + ) + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/OneInchApisModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/OneInchApisModule.kt deleted file mode 100644 index c1ffbe4e87..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/di/OneInchApisModule.kt +++ /dev/null @@ -1,96 +0,0 @@ -package com.tangem.datasource.di - -import android.content.Context -import com.squareup.moshi.Moshi -import com.tangem.datasource.api.oneinch.OneInchApi -import com.tangem.datasource.api.oneinch.OneInchApiFactory -import com.tangem.datasource.utils.RequestHeader -import com.tangem.datasource.utils.addHeaders -import com.tangem.datasource.utils.addLoggers -import com.tangem.lib.auth.AuthBearerProvider -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import okhttp3.OkHttpClient -import retrofit2.Retrofit -import retrofit2.converter.moshi.MoshiConverterFactory -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -class OneInchApisModule { - - @Provides - @Singleton - fun provideOneInchApiFactory( - @NetworkMoshi moshi: Moshi, - @ApplicationContext context: Context, - auth1Inch: AuthBearerProvider, - ): OneInchApiFactory { - val networks = mapOf( - ETH_NETWORK to ONE_INCH_ETH_PATH, - BSC_NETWORK to ONE_INCH_BSC_PATH, - POLYGON_NETWORK to ONE_INCH_POLYGON_PATH, - OPTIMISM_NETWORK to ONE_INCH_OPTIMISM_PATH, - ARBITRUM_NETWORK to ONE_INCH_ARBITRUM_PATH, - GNOSIS_NETWORK to ONE_INCH_GNOSIS_PATH, - AVALANCHE_NETWORK to ONE_INCH_AVALANCHE_PATH, - FANTOM_NETWORK to ONE_INCH_FANTOM_PATH, - ) - - val apiFactory = OneInchApiFactory() - - for ((network, path) in networks) { - apiFactory.putApi( - networkId = network, - api = createOneInchApiWithUrl("$ONE_INCH_BASE_URL$path", moshi, context, auth1Inch), - ) - } - - return apiFactory - } - - private fun createOneInchApiWithUrl( - url: String, - moshi: Moshi, - context: Context, - auth1Inch: AuthBearerProvider, - ): OneInchApi { - return Retrofit.Builder() - .addConverterFactory( - MoshiConverterFactory.create(moshi), - ) - .baseUrl(url) - .client( - OkHttpClient.Builder() - .addHeaders(RequestHeader.AuthBearerHeader(auth1Inch)) - .addLoggers(context) - .build(), - ) - .build() - .create(OneInchApi::class.java) - } - - companion object { - private const val ONE_INCH_BASE_URL = "https://api.1inch.dev/swap/v5.2/" - private const val ONE_INCH_ETH_PATH = "1/" - private const val ONE_INCH_BSC_PATH = "56/" - private const val ONE_INCH_POLYGON_PATH = "137/" - private const val ONE_INCH_OPTIMISM_PATH = "10/" - private const val ONE_INCH_ARBITRUM_PATH = "42161/" - private const val ONE_INCH_GNOSIS_PATH = "100/" - private const val ONE_INCH_AVALANCHE_PATH = "43114/" - private const val ONE_INCH_FANTOM_PATH = "250/" - - private const val ETH_NETWORK = "ethereum" - private const val BSC_NETWORK = "binance-smart-chain" - private const val POLYGON_NETWORK = "polygon-pos" - private const val OPTIMISM_NETWORK = "optimistic-ethereum" - private const val ARBITRUM_NETWORK = "arbitrum-one" - private const val GNOSIS_NETWORK = "xdai" - private const val AVALANCHE_NETWORK = "avalanche" - private const val FANTOM_NETWORK = "fantom" - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/SecurityModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/SecurityModule.kt new file mode 100644 index 0000000000..b5c2f07c49 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/di/SecurityModule.kt @@ -0,0 +1,21 @@ +package com.tangem.datasource.di + +import com.tangem.datasource.config.ConfigManager +import com.tangem.datasource.crypto.DataSignatureVerifier +import com.tangem.datasource.crypto.Sha256SignatureVerifier +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object SecurityModule { + + @Provides + @Singleton + fun provideDataSignatureVerifier(configManager: ConfigManager): DataSignatureVerifier { + return Sha256SignatureVerifier(configManager) + } +} \ No newline at end of file diff --git a/features/swap/data/build.gradle.kts b/features/swap/data/build.gradle.kts index a2b37ee319..12693598d2 100644 --- a/features/swap/data/build.gradle.kts +++ b/features/swap/data/build.gradle.kts @@ -37,6 +37,9 @@ dependencies { /** Tangem SDKs */ implementation(deps.tangem.blockchain) + /** Others */ + implementation(deps.timber) + /** DI */ implementation(deps.hilt.android) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt similarity index 89% rename from features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt rename to features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt index c95e9b4ddf..7a4c0df381 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt @@ -5,6 +5,7 @@ import arrow.core.left import arrow.core.raise.catch import arrow.core.raise.either import arrow.core.right +import com.squareup.moshi.Moshi import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.Result import com.tangem.data.tokens.utils.CryptoCurrencyFactory @@ -13,12 +14,12 @@ import com.tangem.datasource.api.common.response.ApiResponseError import com.tangem.datasource.api.common.response.getOrThrow import com.tangem.datasource.api.express.TangemExpressApi import com.tangem.datasource.api.express.models.request.PairsRequestBody +import com.tangem.datasource.api.express.models.response.ExchangeDataResponseWithTxDetails import com.tangem.datasource.api.express.models.response.SwapPair import com.tangem.datasource.api.express.models.response.SwapPairsWithProviders -import com.tangem.datasource.api.oneinch.OneInchApi -import com.tangem.datasource.api.oneinch.OneInchApiFactory +import com.tangem.datasource.api.express.models.response.TxDetails import com.tangem.datasource.api.tangemTech.TangemTechApi -import com.tangem.datasource.config.ConfigManager +import com.tangem.datasource.crypto.DataSignatureVerifier import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.tokens.model.CryptoCurrency @@ -34,20 +35,23 @@ import com.tangem.feature.swap.domain.models.domain.* import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.async import kotlinx.coroutines.withContext +import timber.log.Timber +import java.io.IOException import java.math.BigDecimal +import java.util.UUID import javax.inject.Inject import com.tangem.datasource.api.express.models.request.LeastTokenInfo as NetworkLeastTokenInfo @Suppress("LongParameterList", "LargeClass") -internal class SwapRepositoryImpl @Inject constructor( +internal class DefaultSwapRepository @Inject constructor( private val tangemTechApi: TangemTechApi, private val tangemExpressApi: TangemExpressApi, - private val oneInchApiFactory: OneInchApiFactory, private val coroutineDispatcher: CoroutineDispatcherProvider, - private val configManager: ConfigManager, private val walletManagersFacade: WalletManagersFacade, private val walletsStateHolder: WalletsStateHolder, private val errorsDataConverter: ErrorsDataConverter, + private val dataSignatureVerifier: DataSignatureVerifier, + moshi: Moshi, ) : SwapRepository { private val tokensConverter = TokensConverter() @@ -56,6 +60,7 @@ internal class SwapRepositoryImpl @Inject constructor( private val swapPairInfoConverter = SwapPairInfoConverter() private val cryptoCurrencyFactory = CryptoCurrencyFactory() private val exchangeStatusConverter = ExchangeStatusConverter() + private val txDetailsMoshiAdapter = moshi.adapter(TxDetails::class.java) override suspend fun getPairs( initialCurrency: LeastTokenInfo, @@ -253,12 +258,6 @@ internal class SwapRepositoryImpl @Inject constructor( } } - override suspend fun addressForTrust(networkId: String): String { - return withContext(coroutineDispatcher.io) { - getOneInchApi(networkId).approveSpender().address - } - } - override suspend fun getExchangeData( fromContractAddress: String, fromNetwork: String, @@ -273,6 +272,7 @@ internal class SwapRepositoryImpl @Inject constructor( ): Either { return withContext(coroutineDispatcher.io) { try { + val requestId = UUID.randomUUID().toString() val response = tangemExpressApi.getExchangeData( fromContractAddress = fromContractAddress, fromNetwork = fromNetwork, @@ -284,16 +284,36 @@ internal class SwapRepositoryImpl @Inject constructor( providerId = providerId, rateType = rateType.name.lowercase(), toAddress = toAddress, + requestId = requestId, ).getOrThrow() - expressDataConverter.convert(response).right() + if (dataSignatureVerifier.verifySignature(response.signature, response.txDetailsJson)) { + val txDetails = parseTxDetails(response.txDetailsJson) + ?: return@withContext DataError.UnknownError.left() + if (txDetails.requestId != requestId) { + return@withContext DataError.InvalidRequestIdError().left() + } + expressDataConverter.convert( + ExchangeDataResponseWithTxDetails( + dataResponse = response, + txDetails = txDetails, + ), + ).right() + } else { + DataError.InvalidSignatureError().left() + } } catch (ex: Exception) { getDataError(ex).left() } } } - override fun getTangemFee(): Double { - return configManager.config.swapReferrerAccount?.fee?.toDoubleOrNull() ?: 0.0 + private fun parseTxDetails(txDetailsJson: String): TxDetails? { + return try { + txDetailsMoshiAdapter.fromJson(txDetailsJson) + } catch (e: IOException) { + Timber.e(e, "error parsing txDetailsJson") + null + } } override suspend fun getAllowance( @@ -367,10 +387,6 @@ internal class SwapRepositoryImpl @Inject constructor( ) } - private fun getOneInchApi(networkId: String): OneInchApi { - return oneInchApiFactory.getApi(networkId) - } - override fun getNativeTokenForNetwork(networkId: String): CryptoCurrency { val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" } diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExpressDataConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExpressDataConverter.kt index 86a75abcb7..d260ec0ef8 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExpressDataConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExpressDataConverter.kt @@ -1,36 +1,42 @@ package com.tangem.feature.swap.converters import com.tangem.datasource.api.express.models.response.ExchangeDataResponse +import com.tangem.datasource.api.express.models.response.ExchangeDataResponseWithTxDetails +import com.tangem.datasource.api.express.models.response.TxDetails import com.tangem.datasource.api.express.models.response.TxType import com.tangem.feature.swap.domain.models.createFromAmountWithOffset import com.tangem.feature.swap.domain.models.domain.ExpressTransactionModel import com.tangem.feature.swap.domain.models.domain.SwapDataModel import com.tangem.utils.converter.Converter -class ExpressDataConverter : Converter { +internal class ExpressDataConverter : Converter { - override fun convert(value: ExchangeDataResponse): SwapDataModel { + override fun convert(value: ExchangeDataResponseWithTxDetails): SwapDataModel { + val data = value.dataResponse return SwapDataModel( - toTokenAmount = createFromAmountWithOffset(value.toAmount, value.toDecimals), - transaction = convertTransaction(value), + toTokenAmount = createFromAmountWithOffset(data.toAmount, data.toDecimals), + transaction = convertTransaction(value.txDetails, data), ) } - private fun convertTransaction(transactionDto: ExchangeDataResponse): ExpressTransactionModel { + private fun convertTransaction( + transactionDto: TxDetails, + dataResponse: ExchangeDataResponse, + ): ExpressTransactionModel { return if (transactionDto.txType == TxType.SWAP) { ExpressTransactionModel.DEX( - fromAmount = createFromAmountWithOffset(transactionDto.fromAmount, transactionDto.fromDecimals), - toAmount = createFromAmountWithOffset(transactionDto.toAmount, transactionDto.toDecimals), - txId = transactionDto.txId, + fromAmount = createFromAmountWithOffset(dataResponse.fromAmount, dataResponse.fromDecimals), + toAmount = createFromAmountWithOffset(dataResponse.toAmount, dataResponse.toDecimals), + txId = dataResponse.txId, txTo = transactionDto.txTo, txFrom = requireNotNull(transactionDto.txFrom), txData = requireNotNull(transactionDto.txData), ) } else { ExpressTransactionModel.CEX( - fromAmount = createFromAmountWithOffset(transactionDto.fromAmount, transactionDto.fromDecimals), - toAmount = createFromAmountWithOffset(transactionDto.toAmount, transactionDto.toDecimals), - txId = transactionDto.txId, + fromAmount = createFromAmountWithOffset(dataResponse.fromAmount, dataResponse.fromDecimals), + toAmount = createFromAmountWithOffset(dataResponse.toAmount, dataResponse.toDecimals), + txId = dataResponse.txId, txTo = transactionDto.txTo, externalTxId = requireNotNull(transactionDto.externalTxId), externalTxUrl = requireNotNull(transactionDto.externalTxUrl), diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt index 83ddab6b62..f48ab71c3a 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt @@ -3,18 +3,17 @@ package com.tangem.feature.swap.di import com.squareup.moshi.Moshi import com.tangem.datasource.api.express.TangemExpressApi import com.tangem.datasource.api.express.models.response.ExpressErrorResponse -import com.tangem.datasource.api.oneinch.OneInchApiFactory import com.tangem.datasource.api.tangemTech.TangemTechApi -import com.tangem.datasource.config.ConfigManager +import com.tangem.datasource.crypto.DataSignatureVerifier import com.tangem.datasource.di.NetworkMoshi import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.WalletsStateHolder -import com.tangem.feature.swap.SwapRepositoryImpl -import com.tangem.feature.swap.converters.ErrorsDataConverter import com.tangem.feature.swap.DefaultSwapTransactionRepository -import com.tangem.feature.swap.domain.api.SwapRepository +import com.tangem.feature.swap.DefaultSwapRepository +import com.tangem.feature.swap.converters.ErrorsDataConverter import com.tangem.feature.swap.domain.SwapTransactionRepository +import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides @@ -31,22 +30,22 @@ internal class SwapDataModule { internal fun provideSwapRepository( tangemTechApi: TangemTechApi, tangemExpressApi: TangemExpressApi, - oneInchApiFactory: OneInchApiFactory, coroutineDispatcher: CoroutineDispatcherProvider, - configManager: ConfigManager, + dataSignature: DataSignatureVerifier, walletManagerFacade: WalletManagersFacade, walletsStateHolder: WalletsStateHolder, errorsDataConverter: ErrorsDataConverter, + @NetworkMoshi moshi: Moshi, ): SwapRepository { - return SwapRepositoryImpl( + return DefaultSwapRepository( tangemTechApi = tangemTechApi, tangemExpressApi = tangemExpressApi, - oneInchApiFactory = oneInchApiFactory, coroutineDispatcher = coroutineDispatcher, - configManager = configManager, walletManagersFacade = walletManagerFacade, walletsStateHolder = walletsStateHolder, errorsDataConverter = errorsDataConverter, + dataSignatureVerifier = dataSignature, + moshi = moshi, ) } diff --git a/features/swap/domain/api/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt b/features/swap/domain/api/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt index c1310c961c..e0182e8a5e 100644 --- a/features/swap/domain/api/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt +++ b/features/swap/domain/api/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt @@ -33,19 +33,6 @@ interface SwapRepository { rateType: RateType, ): Either - /** - * Returns address of 1inch router that must be trusted - * - * @return address - */ - suspend fun addressForTrust(networkId: String): String - - /** - * Returns a tangem fee for swap in percents - * Example: 0.35% - */ - fun getTangemFee(): Double - @Suppress("LongParameterList") @Throws(IllegalStateException::class) suspend fun getAllowance( diff --git a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt index 829cb5e7e4..9c0ca6b268 100644 --- a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt +++ b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt @@ -32,6 +32,10 @@ sealed class DataError { data class UnknownErrorWithCode(override val code: Int) : DataError() + data class InvalidSignatureError(override val code: Int = 990) : DataError() + + data class InvalidRequestIdError(override val code: Int = 991) : DataError() + object UnknownError : DataError() { override val code: Int = -1 } diff --git a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt index 6711df346c..ae50b2dd38 100644 --- a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt +++ b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt @@ -25,7 +25,6 @@ sealed interface SwapState { val permissionState: PermissionDataState = PermissionDataState.Empty, val swapDataModel: SwapDataModel? = null, val txFee: TxFeeState, - val tangemFee: Double, ) : SwapState data class EmptyAmountState( 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 34c9756d26..19a88c1d4a 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 @@ -653,11 +653,6 @@ internal class SwapInteractorImpl @Inject constructor( return repository.getNativeTokenForNetwork(networkId) } - @Deprecated("used in old swap mechanism") - private fun getTangemFee(): Double { - return repository.getTangemFee() - } - private fun getTokenDecimals(token: CryptoCurrency): Int { return if (token is CryptoCurrency.Token) { token.decimals @@ -1013,7 +1008,6 @@ internal class SwapInteractorImpl @Inject constructor( ), networkCurrency = userWalletManager.getNetworkCurrency(networkId), swapDataModel = swapData, - tangemFee = getTangemFee(), txFee = txFeeState, ) } 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 5452767ef8..f02e5006fe 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 @@ -99,7 +99,7 @@ internal class StateBuilder( return uiStateHolder.copy( sendCardData = SwapCardState.SwapCardData( type = TransactionCardType.ReadOnly( - headerResId = R.string.exchange_send_view_header + headerResId = R.string.exchange_send_view_header, ), amountTextFieldValue = TextFieldValue( text = "0", From 1b5518e8b236452eeae5068404e9eecb2cb3ddb5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Dec 2023 20:06:20 +0200 Subject: [PATCH 5/5] Updated on 2026-08-14 --- .../java/com/tangem/tap/di/domain/MnemonicModule.kt | 6 +++--- .../tap/di/domain/WalletManagersFacadeModule.kt | 3 +++ .../tap/features/demo/DemoTransactionSender.kt | 2 +- .../walletmanager/DefaultWalletManagersFacade.kt | 12 +++++++++++- .../onboarding/data/DefaultMnemonicRepository.kt | 2 +- 5 files changed, 19 insertions(+), 6 deletions(-) rename features/onboarding/src/main/java/com/tangem/feature/onboarding/data/di/OnboardingDataModule.kt => app/src/main/java/com/tangem/tap/di/domain/MnemonicModule.kt (77%) diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/di/OnboardingDataModule.kt b/app/src/main/java/com/tangem/tap/di/domain/MnemonicModule.kt similarity index 77% rename from features/onboarding/src/main/java/com/tangem/feature/onboarding/data/di/OnboardingDataModule.kt rename to app/src/main/java/com/tangem/tap/di/domain/MnemonicModule.kt index a853bf6c77..8f62a7e255 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/di/OnboardingDataModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/MnemonicModule.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.onboarding.data.di +package com.tangem.tap.di.domain import android.content.Context import com.tangem.crypto.bip39.Wordlist @@ -14,11 +14,11 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -class OnboardingDataModule { +class MnemonicModule { @Provides @Singleton - fun provideSeedPhraseSdkRepository(@ApplicationContext context: Context): MnemonicRepository { + fun provideMnemonicRepository(@ApplicationContext context: Context): MnemonicRepository { return DefaultMnemonicRepository(Wordlist.getWordlist(context)) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt b/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt index 63afaaeaf2..02a52ce342 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt @@ -8,6 +8,7 @@ import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.datasource.local.walletmanager.WalletManagersStore import com.tangem.domain.walletmanager.DefaultWalletManagersFacade import com.tangem.domain.walletmanager.WalletManagersFacade +import com.tangem.feature.onboarding.data.MnemonicRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -24,6 +25,7 @@ internal object WalletManagersFacadeModule { walletManagersStore: WalletManagersStore, userWalletsStore: UserWalletsStore, configManager: ConfigManager, + mnemonicRepository: MnemonicRepository, assetReader: AssetReader, @SdkMoshi moshi: Moshi, ): WalletManagersFacade { @@ -33,6 +35,7 @@ internal object WalletManagersFacadeModule { configManager = configManager, assetReader = assetReader, moshi = moshi, + mnemonic = mnemonicRepository.generateDefaultMnemonic(), ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoTransactionSender.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoTransactionSender.kt index 17714e011b..faecf5aac1 100644 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoTransactionSender.kt +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoTransactionSender.kt @@ -21,7 +21,7 @@ class DemoTransactionSender(private val walletManager: WalletManager) : Transact ) } - override suspend fun estimateFee(amount: Amount): Result { + override suspend fun estimateFee(amount: Amount, destination: String): Result { return getFee(amount, walletManager.wallet.address) } diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt index cdffab603a..03cdd7a611 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt @@ -10,11 +10,13 @@ import com.tangem.blockchain.blockchains.solana.RentProvider import com.tangem.blockchain.common.* import com.tangem.blockchain.common.address.Address import com.tangem.blockchain.common.address.AddressType +import com.tangem.blockchain.common.address.EstimationFeeAddressFactory import com.tangem.blockchain.common.transaction.Fee import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.blockchain.common.txhistory.TransactionHistoryRequest import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.SimpleResult +import com.tangem.crypto.bip39.Mnemonic import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.datasource.asset.AssetReader import com.tangem.datasource.config.ConfigManager @@ -45,6 +47,7 @@ class DefaultWalletManagersFacade( private val walletManagersStore: WalletManagersStore, private val userWalletsStore: UserWalletsStore, configManager: ConfigManager, + mnemonic: Mnemonic, assetReader: AssetReader, moshi: Moshi, ) : WalletManagersFacade { @@ -55,6 +58,7 @@ class DefaultWalletManagersFacade( private val sdkTokenConverter by lazy { SdkTokenConverter() } private val txHistoryStateConverter by lazy { SdkTransactionHistoryStateConverter() } private val txHistoryItemConverter by lazy { SdkTransactionHistoryItemConverter(assetReader, moshi) } + private val estimationFeeAddressFactory by lazy { EstimationFeeAddressFactory(mnemonic) } override suspend fun update( userWalletId: UserWalletId, @@ -444,7 +448,13 @@ class DefaultWalletManagersFacade( blockchain = blockchain, derivationPath = network.derivationPath.value, ) - return (walletManager as? TransactionSender)?.estimateFee(amount = amount) + + val destination = estimationFeeAddressFactory.makeAddress(blockchain) + + return (walletManager as? TransactionSender)?.estimateFee( + amount = amount, + destination = destination, + ) } override suspend fun validateTransaction( diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/DefaultMnemonicRepository.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/DefaultMnemonicRepository.kt index 9cb238b99e..71ac3393b7 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/DefaultMnemonicRepository.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/DefaultMnemonicRepository.kt @@ -8,7 +8,7 @@ import com.tangem.crypto.bip39.Wordlist /** [REDACTED_AUTHOR] */ -internal class DefaultMnemonicRepository( +class DefaultMnemonicRepository( private val bip39Wordlist: Wordlist, ) : MnemonicRepository {