diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 63fbb50de7..a15171a939 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -108,10 +108,10 @@ repositories { dependencies { implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar")))) implementation(project(":domain")) - implementation(project(":network")) implementation(project(":common")) implementation(project(":core:res")) implementation(project(":core:ui")) + implementation(project(":core:datasource")) implementation(project(":core:utils")) implementation(project(":libs:crypto")) implementation(project(":libs:auth")) @@ -120,6 +120,9 @@ dependencies { implementation(project(":features:referral:presentation")) implementation(project(":features:referral:domain")) implementation(project(":features:referral:data")) + implementation(project(":features:swap:presentation")) + implementation(project(":features:swap:domain")) + implementation(project(":features:swap:data")) /** AndroidX libraries */ implementation(AndroidX.coreKtx) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index bfc2bf8157..897f0f7c40 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit bfc2bf8157089bce6b44779bdae66df2c920de70 +Subproject commit 897f0f7c402fd53c5ee1fa4ab601ecd4e43ff389 diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 41b4fb59bb..d17e83bd33 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -11,9 +11,9 @@ import com.tangem.blockchain.common.BlockchainSdkConfig import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder import com.tangem.common.json.MoshiJsonConverter +import com.tangem.datasource.api.common.MoshiConverter import com.tangem.domain.DomainLayer import com.tangem.domain.common.LogConfig -import com.tangem.network.common.MoshiConverter import com.tangem.tap.common.AndroidAssetReader import com.tangem.tap.common.AssetReader import com.tangem.tap.common.analytics.Analytics @@ -156,6 +156,7 @@ class TapApplication : Application(), ImageLoaderFactory { appStateHolder.userTokensRepository = userTokensRepository } + //todo refactor: move to datasource and provide via DI private fun initMoshiConverter() { fun appAdapters(): List = listOf( BigDecimalAdapter(), diff --git a/app/src/main/java/com/tangem/tap/domain/RatesRepository.kt b/app/src/main/java/com/tangem/tap/domain/RatesRepository.kt index 8b4136e90f..7cee3bcfd9 100644 --- a/app/src/main/java/com/tangem/tap/domain/RatesRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/RatesRepository.kt @@ -2,7 +2,7 @@ package com.tangem.tap.domain import com.tangem.common.services.Result import com.tangem.domain.common.ThrottlerWithValues -import com.tangem.network.api.tangemTech.TangemTechService +import com.tangem.datasource.api.tangemTech.TangemTechService import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.store import java.math.BigDecimal diff --git a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt index 0bc9a2c283..aae3cf8e9a 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt @@ -2,7 +2,7 @@ package com.tangem.tap.domain import androidx.annotation.StringRes import com.tangem.common.core.TangemError -import com.tangem.network.api.tangemTech.TangemTechError +import com.tangem.datasource.api.tangemTech.TangemTechError import com.tangem.wallet.R interface TapErrors diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt b/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt index 6e94b5a88a..0e18c4018d 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt @@ -3,7 +3,7 @@ package com.tangem.tap.domain.tokens import com.squareup.moshi.JsonClass import com.tangem.blockchain.common.Blockchain import com.tangem.domain.common.extensions.fromNetworkId -import com.tangem.network.api.tangemTech.CoinsResponse +import com.tangem.datasource.api.tangemTech.CoinsResponse @JsonClass(generateAdapter = true) data class CurrencyFromJson( diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt index 7df68e80c3..fbbaad9022 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt @@ -6,9 +6,9 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.common.services.Result import com.tangem.domain.common.extensions.getListOfCoins import com.tangem.domain.common.extensions.toNetworkId -import com.tangem.network.api.tangemTech.CoinsResponse -import com.tangem.network.api.tangemTech.TangemTechService -import com.tangem.network.common.MoshiConverter +import com.tangem.datasource.api.tangemTech.CoinsResponse +import com.tangem.datasource.api.tangemTech.TangemTechService +import com.tangem.datasource.api.common.MoshiConverter import com.tangem.tap.common.AssetReader class LoadAvailableCoinsService( diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt index 7418891662..2aa1dce1a7 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt @@ -7,8 +7,8 @@ import com.tangem.blockchain.common.DerivationStyle import com.tangem.common.services.Result import com.tangem.domain.common.extensions.getTokens import com.tangem.domain.common.extensions.toNetworkId -import com.tangem.network.api.tangemTech.TangemTechService -import com.tangem.network.common.MoshiConverter +import com.tangem.datasource.api.tangemTech.TangemTechService +import com.tangem.datasource.api.common.MoshiConverter import com.tangem.tap.common.FileReader import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.domain.tokens.models.TokenDao diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensNetworkService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensNetworkService.kt index c0b7e18155..821a8046ac 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensNetworkService.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensNetworkService.kt @@ -2,8 +2,8 @@ package com.tangem.tap.domain.tokens import com.tangem.common.core.TangemSdkError import com.tangem.common.services.Result -import com.tangem.network.api.tangemTech.TangemTechService -import com.tangem.network.api.tangemTech.UserTokensResponse +import com.tangem.datasource.api.tangemTech.TangemTechService +import com.tangem.datasource.api.tangemTech.UserTokensResponse import com.tangem.tap.domain.NoDataError class UserTokensNetworkService(private val tangemTechService: TangemTechService) { diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt index 4d6646ed32..6fb7de9ad7 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt @@ -3,10 +3,10 @@ package com.tangem.tap.domain.tokens import android.content.Context import com.tangem.blockchain.common.DerivationStyle import com.tangem.common.services.Result +import com.tangem.datasource.api.tangemTech.TangemTechService +import com.tangem.datasource.api.tangemTech.UserTokensResponse import com.tangem.domain.common.CardDTO import com.tangem.domain.common.util.userWalletId -import com.tangem.network.api.tangemTech.TangemTechService -import com.tangem.network.api.tangemTech.UserTokensResponse import com.tangem.tap.common.AndroidFileReader import com.tangem.tap.domain.NoDataError import com.tangem.tap.domain.tokens.models.BlockchainNetwork diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt index 5f36f9bd49..9e5dac0b68 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt @@ -2,9 +2,9 @@ package com.tangem.tap.domain.tokens import com.squareup.moshi.JsonAdapter import com.tangem.Log +import com.tangem.datasource.api.tangemTech.UserTokensResponse +import com.tangem.datasource.api.common.MoshiConverter import com.tangem.domain.common.CardDTO -import com.tangem.network.api.tangemTech.UserTokensResponse -import com.tangem.network.common.MoshiConverter import com.tangem.tap.common.FileReader import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.toCurrencies diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt index 9aed6f968c..7917ddaa07 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt @@ -10,7 +10,7 @@ import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ScanResponse -import com.tangem.network.common.MoshiConverter +import com.tangem.datasource.api.common.MoshiConverter import com.tangem.operations.wallet.CreateWalletResponse import com.tangem.tap.common.AssetReader import com.tangem.tap.tangemSdkManager diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt index 315606c659..7fc7ba38e7 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt @@ -1,7 +1,7 @@ package com.tangem.tap.domain.walletStores.repository.di import com.tangem.blockchain.common.WalletManagerFactory -import com.tangem.network.api.tangemTech.TangemTechService +import com.tangem.datasource.api.tangemTech.TangemTechService import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index df28ac9d4c..fd8a037dba 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -14,9 +14,9 @@ import com.tangem.common.flatMap import com.tangem.common.flatMapOnFailure import com.tangem.common.map import com.tangem.common.services.Result +import com.tangem.datasource.api.tangemTech.TangemTechService import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.util.UserWalletId -import com.tangem.network.api.tangemTech.TangemTechService import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.replaceByOrAdd import com.tangem.tap.domain.model.UserWallet diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectRepository.kt index 543640ad2f..c796b81261 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectRepository.kt @@ -7,7 +7,7 @@ import com.squareup.moshi.JsonClass import com.squareup.moshi.Types import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString -import com.tangem.network.common.MoshiConverter +import com.tangem.datasource.api.common.MoshiConverter import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession import com.tangem.tap.features.details.redux.walletconnect.WalletForSession import com.trustwallet.walletconnect.models.WCPeerMeta @@ -18,7 +18,7 @@ import java.nio.charset.Charset class WalletConnectRepository(val context: Application) { private val moshi = MoshiConverter.defaultMoshi() private val walletConnectAdapter: JsonAdapter> = moshi.adapter( - Types.newParameterizedType(List::class.java, SessionDao::class.java) + Types.newParameterizedType(List::class.java, SessionDao::class.java), ) fun saveSession(session: WalletConnectSession) { @@ -76,7 +76,6 @@ class WalletConnectRepository(val context: Application) { } } - @JsonClass(generateAdapter = true) data class SessionDao( val peerId: String, @@ -91,7 +90,7 @@ data class SessionDao( remotePeerId = remotePeerId, wallet = wallet, session = session, - peerMeta = peerMeta + peerMeta = peerMeta, ) } @@ -102,7 +101,7 @@ data class SessionDao( remotePeerId = session.remotePeerId, wallet = session.wallet, session = session.session, - peerMeta = session.peerMeta + peerMeta = session.peerMeta, ) } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt index 04933d0a46..187425c2af 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt @@ -12,13 +12,13 @@ import com.tangem.common.extensions.isZero import com.tangem.common.services.Result import com.tangem.domain.common.extensions.successOr import com.tangem.domain.common.util.UserWalletId -import com.tangem.network.api.paymentology.AttestationResponse -import com.tangem.network.api.paymentology.PaymentologyApiService -import com.tangem.network.api.paymentology.RegisterKYCRequest -import com.tangem.network.api.paymentology.RegisterWalletRequest -import com.tangem.network.api.paymentology.RegisterWalletResponse -import com.tangem.network.api.paymentology.RegistrationResponse -import com.tangem.network.api.paymentology.tryExtractError +import com.tangem.datasource.api.paymentology.AttestationResponse +import com.tangem.datasource.api.paymentology.PaymentologyApiService +import com.tangem.datasource.api.paymentology.RegisterKYCRequest +import com.tangem.datasource.api.paymentology.RegisterWalletRequest +import com.tangem.datasource.api.paymentology.RegisterWalletResponse +import com.tangem.datasource.api.paymentology.RegistrationResponse +import com.tangem.datasource.api.paymentology.tryExtractError import com.tangem.operations.attestation.AttestWalletKeyResponse import com.tangem.tap.common.extensions.safeUpdate import com.tangem.tap.domain.getFirstToken @@ -152,12 +152,13 @@ class SaltPayActivationManager( ) } - private fun makeRegisterKYCRequest(): RegisterKYCRequest = RegisterKYCRequest( - cardId = cardId, - publicKey = cardPublicKey, - kycProvider = "UTORG", - kycRefId = kycUrlProvider.kycRefId, - ) + private fun makeRegisterKYCRequest(): RegisterKYCRequest = + RegisterKYCRequest( + cardId = cardId, + publicKey = cardPublicKey, + kycProvider = "UTORG", + kycRefId = kycUrlProvider.kycRefId, + ) companion object { fun stub(): SaltPayActivationManager = SaltPayActivationManager( diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index 69f3e0a674..4d6c4a3c00 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -8,8 +8,8 @@ import com.tangem.common.extensions.guard import com.tangem.common.services.Result import com.tangem.domain.common.extensions.successOr import com.tangem.domain.common.extensions.withMainContext -import com.tangem.network.api.paymentology.KYCStatus -import com.tangem.network.api.paymentology.RegistrationResponse +import com.tangem.datasource.api.paymentology.KYCStatus +import com.tangem.datasource.api.paymentology.RegistrationResponse import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDebugErrorNotification diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt index 6acbe4bdd2..e1317622a4 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt @@ -6,7 +6,7 @@ import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.common.extensions.guard import com.tangem.domain.common.SaltPayWorkaround import com.tangem.domain.common.ScanResponse -import com.tangem.network.api.paymentology.PaymentologyApiService +import com.tangem.datasource.api.paymentology.PaymentologyApiService import com.tangem.tap.common.toggleWidget.WidgetState import com.tangem.tap.domain.extensions.makeSaltPayWalletManager import com.tangem.tap.features.onboarding.products.wallet.saltPay.GnosisRegistrator diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt index 4c5dd07560..146d622d16 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt @@ -5,7 +5,7 @@ import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.domain.common.extensions.toCoinId import com.tangem.domain.common.extensions.toNetworkId import com.tangem.domain.features.addCustomToken.CustomCurrency -import com.tangem.network.api.tangemTech.TokenResponse +import com.tangem.datasource.api.tangemTech.TokenResponse import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.tokens.redux.TokenWithBlockchain diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt index d0720a000c..c60632f60e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt @@ -1,8 +1,8 @@ package com.tangem.tap.features.wallet.redux.middlewares import com.tangem.common.services.Result -import com.tangem.network.api.tangemTech.CurrenciesResponse -import com.tangem.network.api.tangemTech.TangemTechService +import com.tangem.datasource.api.tangemTech.CurrenciesResponse +import com.tangem.datasource.api.tangemTech.TangemTechService import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.MainScreen diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt index 35cc636808..9dd2b9746f 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt @@ -6,7 +6,7 @@ import com.tangem.common.extensions.calculateSha512 import com.tangem.common.extensions.toHexString import com.tangem.common.services.Result import com.tangem.common.services.performRequest -import com.tangem.network.common.createRetrofitInstance +import com.tangem.datasource.api.common.createRetrofitInstance import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt index 5e52716d98..645d5182ed 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt @@ -6,7 +6,7 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.common.services.Result import com.tangem.common.services.performRequest import com.tangem.domain.common.extensions.withIOContext -import com.tangem.network.common.createRetrofitInstance +import com.tangem.datasource.api.common.createRetrofitInstance import com.tangem.tap.common.extensions.urlEncode import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.features.wallet.models.Currency diff --git a/app/src/main/java/com/tangem/tap/network/payid/PayIdService.kt b/app/src/main/java/com/tangem/tap/network/payid/PayIdService.kt index f4612643d3..d9cc63b72a 100644 --- a/app/src/main/java/com/tangem/tap/network/payid/PayIdService.kt +++ b/app/src/main/java/com/tangem/tap/network/payid/PayIdService.kt @@ -3,7 +3,7 @@ package com.tangem.tap.network.payid import com.squareup.moshi.JsonClass import com.tangem.common.services.Result import com.tangem.common.services.performRequest -import com.tangem.network.common.createRetrofitInstance +import com.tangem.datasource.api.common.createRetrofitInstance import retrofit2.Retrofit class PayIdService { diff --git a/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyService.kt b/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyService.kt index f5e7ed1f96..05d16f8724 100644 --- a/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyService.kt +++ b/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyService.kt @@ -2,7 +2,7 @@ package com.tangem.tap.network.payid import com.tangem.common.services.Result import com.tangem.common.services.performRequest -import com.tangem.network.common.createRetrofitInstance +import com.tangem.datasource.api.common.createRetrofitInstance /** [REDACTED_AUTHOR] diff --git a/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt b/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt index 50a8859516..59c500f9a7 100644 --- a/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt @@ -3,7 +3,7 @@ package com.tangem.tap.persistence import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter -import com.tangem.network.api.tangemTech.CurrenciesResponse +import com.tangem.datasource.api.tangemTech.CurrenciesResponse import com.tangem.tap.common.entities.FiatCurrency /** diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt index 413f292589..4f4d41a9e4 100644 --- a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt @@ -4,7 +4,7 @@ import android.app.Application import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit -import com.tangem.network.common.MoshiConverter +import com.tangem.datasource.api.common.MoshiConverter import java.util.* class PreferencesStorage(applicationContext: Application) { diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts index df394557fd..082885c1d7 100644 --- a/core/datasource/build.gradle.kts +++ b/core/datasource/build.gradle.kts @@ -42,6 +42,9 @@ dependencies { /** Project */ implementation(project(":libs:auth")) + /** Tangem libraries */ + implementation(Tangem.cardCore) + /** DI */ implementation(Library.hilt) kapt(Library.hiltKapt) diff --git a/network/src/main/java/com/tangem/network/common/Interceptors.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/Interceptors.kt similarity index 69% rename from network/src/main/java/com/tangem/network/common/Interceptors.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/common/Interceptors.kt index bc46e5a0a0..17b348b924 100644 --- a/network/src/main/java/com/tangem/network/common/Interceptors.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/Interceptors.kt @@ -1,4 +1,4 @@ -package com.tangem.network.common +package com.tangem.datasource.api.common import okhttp3.Interceptor import okhttp3.Response @@ -7,7 +7,7 @@ import okhttp3.Response [REDACTED_AUTHOR] */ open class AddHeaderInterceptor( - private val headers: Map + private val headers: Map, ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { @@ -21,10 +21,10 @@ open class AddHeaderInterceptor( } } -class CacheControlHttpInterceptor(maxAgeSeconds: Int) : AddHeaderInterceptor(mapOf( - "Cache-Control" to "max-age=$maxAgeSeconds", -)) +class CacheControlHttpInterceptor(maxAgeSeconds: Int) : AddHeaderInterceptor( + mapOf("Cache-Control" to "max-age=$maxAgeSeconds"), +) -class CardPublicKeyHttpInterceptor(cardPublicKeyHex: String) : AddHeaderInterceptor(mapOf( - "card_public_key" to cardPublicKeyHex, -)) \ No newline at end of file +class CardPublicKeyHttpInterceptor(cardPublicKeyHex: String) : AddHeaderInterceptor( + mapOf("card_public_key" to cardPublicKeyHex), +) \ No newline at end of file diff --git a/network/src/main/java/com/tangem/network/common/MoshiConverter.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/MoshiConverter.kt similarity index 79% rename from network/src/main/java/com/tangem/network/common/MoshiConverter.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/common/MoshiConverter.kt index 47b5cc4b64..054206db9d 100644 --- a/network/src/main/java/com/tangem/network/common/MoshiConverter.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/MoshiConverter.kt @@ -1,4 +1,4 @@ -package com.tangem.network.common +package com.tangem.datasource.api.common import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi @@ -9,8 +9,10 @@ import retrofit2.converter.moshi.MoshiConverterFactory /** [REDACTED_AUTHOR] */ +//todo needs to be refactored object MoshiConverter { + //todo refactor: provide via DI var INSTANCE = MoshiJsonConverter() private set @@ -23,7 +25,9 @@ object MoshiConverter { fun createFactory(moshi: Moshi = INSTANCE.moshi): Converter.Factory = MoshiConverterFactory.create(moshi) + //todo provide via DI using quealifiers fun defaultMoshi(): Moshi = INSTANCE.moshi + //todo provide via DI using quealifiers fun sdkMoshi(): Moshi = MoshiJsonConverter.INSTANCE.moshi } \ No newline at end of file diff --git a/network/src/main/java/com/tangem/network/common/Retrofit.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/Retrofit.kt similarity index 96% rename from network/src/main/java/com/tangem/network/common/Retrofit.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/common/Retrofit.kt index 70bb657bce..01e19dfada 100644 --- a/network/src/main/java/com/tangem/network/common/Retrofit.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/Retrofit.kt @@ -1,4 +1,4 @@ -package com.tangem.network.common +package com.tangem.datasource.api.common import okhttp3.Interceptor import okhttp3.OkHttpClient 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 new file mode 100644 index 0000000000..774d001e04 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/OneInchApi.kt @@ -0,0 +1,200 @@ +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.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, + ): AllowanceResponse + //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] + */ + suspend fun quote( + @Query("fromTokenAddress") fromTokenAddress: String, + @Query("toTokenAddress") 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, + ): QuoteResponse + + /** + * 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] + */ + suspend fun swap( + @Query("fromTokenAddress") fromTokenAddress: String, + @Query("toTokenAddress") toTokenAddress: String, + @Query("amount") amount: String, + @Query("fromAddress") fromAddress: String, + @Query("slippage") slippage: Int, + @Query("protocols") protocols: String? = null, + @Query("destReceiver") destinationAddress: String? = null, + @Query("referrerAddress") referrerAddress: String? = null, + @Query("fee") fee: String? = null, + @Query("disableEstimate") disableEstimate: Boolean? = null, + @Query("permit") permit: String? = null, + @Query("compatibilityMode") 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, + ): SwapResponse + //endregion Swap +} \ 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 new file mode 100644 index 0000000000..16956f907e --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/AllowanceResponse.kt @@ -0,0 +1,7 @@ +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 new file mode 100644 index 0000000000..f57fab94fd --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveCalldataResponse.kt @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000000..0ee9d5b2ac --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ApproveSpenderResponse.kt @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000000..03c23155ff --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/PathViewDto.kt @@ -0,0 +1,13 @@ +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 new file mode 100644 index 0000000000..b083cd1ce8 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/ProtocolsResponse.kt @@ -0,0 +1,27 @@ +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 new file mode 100644 index 0000000000..dca5642f12 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/QuoteResponse.kt @@ -0,0 +1,22 @@ +package com.tangem.datasource.api.oneinch.models + +import com.squareup.moshi.Json + +/** + * Quote response + * + * @property fromToken Source token info + * @property toToken Destination token info + * @property toTokenAmount Expected amount of destination token + * @property fromTokenAmount Amount of source token + * @property protocols Selected protocols in a path + * @property estimatedGas gas fee + */ +data class QuoteResponse( + @Json(name = "fromToken") val fromToken: TokenOneInchDto, + @Json(name = "toToken") val toToken: TokenOneInchDto, + @Json(name = "toTokenAmount") val toTokenAmount: String, + @Json(name = "fromTokenAmount") val fromTokenAmount: String, + @Json(name = "protocols") val protocols: List, + @Json(name = "estimatedGas") val estimatedGas: Int, +) \ 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 new file mode 100644 index 0000000000..576851a3b5 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/StatusResponse.kt @@ -0,0 +1,8 @@ +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 new file mode 100644 index 0000000000..fe342de231 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapErrorDto.kt @@ -0,0 +1,42 @@ +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 new file mode 100644 index 0000000000..1f25a391e0 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/SwapResponse.kt @@ -0,0 +1,12 @@ +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 = "toTokenAmount") val toTokenAmount: String, + @Json(name = "fromTokenAmount") val fromTokenAmount: String, + @Json(name = "protocols") val protocols: List, + @Json(name = "transaction") 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 new file mode 100644 index 0000000000..0c06f15d84 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokenOneInchDto.kt @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000000..ca1b369949 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TokensResponse.kt @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000000..a32e827601 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/oneinch/models/TransactionDto.kt @@ -0,0 +1,23 @@ +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/network/src/main/java/com/tangem/network/api/paymentology/PaymentologyApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/paymentology/PaymentologyApi.kt similarity index 95% rename from network/src/main/java/com/tangem/network/api/paymentology/PaymentologyApi.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/paymentology/PaymentologyApi.kt index 058cd368dd..de7c678d3b 100644 --- a/network/src/main/java/com/tangem/network/api/paymentology/PaymentologyApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/paymentology/PaymentologyApi.kt @@ -1,4 +1,4 @@ -package com.tangem.network.api.paymentology +package com.tangem.datasource.api.paymentology import retrofit2.http.Body import retrofit2.http.Headers diff --git a/network/src/main/java/com/tangem/network/api/paymentology/PaymentologyApiService.kt b/core/datasource/src/main/java/com/tangem/datasource/api/paymentology/PaymentologyApiService.kt similarity index 91% rename from network/src/main/java/com/tangem/network/api/paymentology/PaymentologyApiService.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/paymentology/PaymentologyApiService.kt index 8cd70891c3..f46a17b36d 100644 --- a/network/src/main/java/com/tangem/network/api/paymentology/PaymentologyApiService.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/paymentology/PaymentologyApiService.kt @@ -1,10 +1,10 @@ -package com.tangem.network.api.paymentology +package com.tangem.datasource.api.paymentology import com.tangem.common.extensions.toHexString import com.tangem.common.services.Result import com.tangem.common.services.performRequest -import com.tangem.network.common.MoshiConverter -import com.tangem.network.common.createRetrofitInstance +import com.tangem.datasource.api.common.MoshiConverter +import com.tangem.datasource.api.common.createRetrofitInstance import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/network/src/main/java/com/tangem/network/api/paymentology/Requests.kt b/core/datasource/src/main/java/com/tangem/datasource/api/paymentology/Requests.kt similarity index 98% rename from network/src/main/java/com/tangem/network/api/paymentology/Requests.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/paymentology/Requests.kt index 580e60bfa5..cb0206934e 100644 --- a/network/src/main/java/com/tangem/network/api/paymentology/Requests.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/paymentology/Requests.kt @@ -1,4 +1,4 @@ -package com.tangem.network.api.paymentology +package com.tangem.datasource.api.paymentology import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/network/src/main/java/com/tangem/network/api/paymentology/Responses.kt b/core/datasource/src/main/java/com/tangem/datasource/api/paymentology/Responses.kt similarity index 98% rename from network/src/main/java/com/tangem/network/api/paymentology/Responses.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/paymentology/Responses.kt index b60324b42d..d62630b73e 100644 --- a/network/src/main/java/com/tangem/network/api/paymentology/Responses.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/paymentology/Responses.kt @@ -1,4 +1,4 @@ -package com.tangem.network.api.paymentology +package com.tangem.datasource.api.paymentology import com.squareup.moshi.Json import com.tangem.common.extensions.calculateHashCode diff --git a/network/src/main/java/com/tangem/network/api/tangemTech/Responses.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/Responses.kt similarity index 90% rename from network/src/main/java/com/tangem/network/api/tangemTech/Responses.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/Responses.kt index 4f88fca3b7..532a5debfb 100644 --- a/network/src/main/java/com/tangem/network/api/tangemTech/Responses.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/Responses.kt @@ -1,4 +1,4 @@ -package com.tangem.network.api.tangemTech +package com.tangem.datasource.api.tangemTech import java.math.BigDecimal @@ -11,7 +11,7 @@ sealed interface TangemTechResponse : HttpResponse data class CoinsResponse( val imageHost: String?, val coins: List, - val total: Int + val total: Int, ) : TangemTechResponse { data class Coin( @@ -19,13 +19,14 @@ data class CoinsResponse( val name: String, val symbol: String, val active: Boolean, - val networks: List = listOf() + val networks: List = listOf(), ) : TangemTechResponse { data class Network( val networkId: String, val contractAddress: String? = null, val decimalCount: BigDecimal? = null, + val exchangeable: Boolean? = false, ) : TangemTechResponse } } diff --git a/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt similarity index 87% rename from network/src/main/java/com/tangem/network/api/tangemTech/TangemTechApi.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt index 518edd9fec..e518041674 100644 --- a/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt @@ -1,4 +1,4 @@ -package com.tangem.network.api.tangemTech +package com.tangem.datasource.api.tangemTech import retrofit2.http.Body import retrofit2.http.GET @@ -14,11 +14,12 @@ interface TangemTechApi { @GET("coins") suspend fun coins( @Query("contractAddress") contractAddress: String? = null, + @Query("exchangeable") exchangeable: Boolean? = false, @Query("networkIds") networkIds: String? = null, @Query("active") active: Boolean? = null, @Query("searchText") searchText: String? = null, @Query("offset") offset: Int? = null, - @Query("limit") limit: Int? = null + @Query("limit") limit: Int? = null, ): CoinsResponse @GET("rates") diff --git a/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechService.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechService.kt similarity index 91% rename from network/src/main/java/com/tangem/network/api/tangemTech/TangemTechService.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechService.kt index 6137e8dfa0..50540a226e 100644 --- a/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechService.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechService.kt @@ -1,10 +1,10 @@ -package com.tangem.network.api.tangemTech +package com.tangem.datasource.api.tangemTech import com.tangem.common.services.Result import com.tangem.common.services.performRequest -import com.tangem.network.common.AddHeaderInterceptor -import com.tangem.network.common.CacheControlHttpInterceptor -import com.tangem.network.common.createRetrofitInstance +import com.tangem.datasource.api.common.AddHeaderInterceptor +import com.tangem.datasource.api.common.CacheControlHttpInterceptor +import com.tangem.datasource.api.common.createRetrofitInstance import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt index 6fed866ecc..d662a98721 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt @@ -3,7 +3,10 @@ package com.tangem.datasource.di import com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.tangem.datasource.api.AuthHeaderInterceptor +import com.tangem.datasource.api.oneinch.OneInchApi import com.tangem.datasource.api.referral.ReferralApi +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.di.qualifiers.OneInchEthereum import com.tangem.lib.auth.AuthProvider import dagger.Module import dagger.Provides @@ -19,6 +22,33 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) class NetworkModule { + @Provides + @Singleton + fun provideTangemTechApi(okHttpClient: OkHttpClient): TangemTechApi { + return Retrofit.Builder() + .addConverterFactory( + MoshiConverterFactory.create(), + ) + .baseUrl(DEV_TANGEM_TECH_BASE_URL) + .client(okHttpClient) + .build() + .create(TangemTechApi::class.java) + } + + @Provides + @Singleton + @OneInchEthereum + fun provideOneInchEthereumApi(): OneInchApi { + return Retrofit.Builder() + .addConverterFactory( + MoshiConverterFactory.create(), + ) + .baseUrl(ONE_INCH_ETHER_BASE_URL) + .client(OkHttpClient()) + .build() + .create(OneInchApi::class.java) + } + @Provides @Singleton fun provideReferralApi(okHttpClient: OkHttpClient): ReferralApi { @@ -30,7 +60,7 @@ class NetworkModule { .build(), ), ) - .baseUrl(PROD_REFERRAL_BASE_URL) + .baseUrl(DEV_TANGEM_TECH_BASE_URL) .client(okHttpClient) .build() .create(ReferralApi::class.java) @@ -48,6 +78,8 @@ class NetworkModule { } private companion object { - const val PROD_REFERRAL_BASE_URL = "https://devapi.tangem-tech.com/v1/"//"https://api.tangem-tech.com/v1/" + const val PROD_TANGEM_TECH_BASE_URL = "https://api.tangem-tech.com/v1/" + const val DEV_TANGEM_TECH_BASE_URL = "https://devapi.tangem-tech.com/v1/" + const val ONE_INCH_ETHER_BASE_URL = "" } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/qualifiers/OneInchApiQualifiers.kt b/core/datasource/src/main/java/com/tangem/datasource/di/qualifiers/OneInchApiQualifiers.kt new file mode 100644 index 0000000000..f312541fde --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/di/qualifiers/OneInchApiQualifiers.kt @@ -0,0 +1,15 @@ +package com.tangem.datasource.di.qualifiers + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class OneInchEthereum + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class OneInchBinance + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class OneInchOptimism \ No newline at end of file diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index 6909db2791..e365d69c25 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -71,7 +71,7 @@ android { } dependencies { - implementation(project(":network")) + implementation(project(":core:datasource")) implementation(project(":common")) /** Tangem libraries */ diff --git a/domain/src/main/java/com/tangem/domain/DomainDialog.kt b/domain/src/main/java/com/tangem/domain/DomainDialog.kt index bc7d30a7da..22e0ae8e28 100644 --- a/domain/src/main/java/com/tangem/domain/DomainDialog.kt +++ b/domain/src/main/java/com/tangem/domain/DomainDialog.kt @@ -1,7 +1,7 @@ package com.tangem.domain import com.tangem.common.extensions.VoidCallback -import com.tangem.network.api.tangemTech.CoinsResponse +import com.tangem.datasource.api.tangemTech.CoinsResponse /** [REDACTED_AUTHOR] diff --git a/domain/src/main/java/com/tangem/domain/common/extensions/TangemTechService.kt b/domain/src/main/java/com/tangem/domain/common/extensions/TangemTechService.kt index 3304349b69..925eaa5f82 100644 --- a/domain/src/main/java/com/tangem/domain/common/extensions/TangemTechService.kt +++ b/domain/src/main/java/com/tangem/domain/common/extensions/TangemTechService.kt @@ -1,8 +1,8 @@ package com.tangem.domain.common.extensions import com.tangem.common.services.Result -import com.tangem.network.api.tangemTech.CoinsResponse -import com.tangem.network.api.tangemTech.TangemTechService +import com.tangem.datasource.api.tangemTech.CoinsResponse +import com.tangem.datasource.api.tangemTech.TangemTechService suspend fun TangemTechService.getTokens( contractAddress: String, diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenService.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenService.kt index a502ae5041..98a63b6565 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenService.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenService.kt @@ -2,8 +2,8 @@ package com.tangem.domain.features.addCustomToken import com.tangem.common.services.Result import com.tangem.domain.common.extensions.getTokens -import com.tangem.network.api.tangemTech.CoinsResponse -import com.tangem.network.api.tangemTech.TangemTechService +import com.tangem.datasource.api.tangemTech.CoinsResponse +import com.tangem.datasource.api.tangemTech.TangemTechService /** [REDACTED_AUTHOR] diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenAction.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenAction.kt index 6949c1de51..3a5946f963 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenAction.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenAction.kt @@ -8,7 +8,7 @@ import com.tangem.domain.common.form.Field import com.tangem.domain.common.form.FieldId import com.tangem.domain.features.addCustomToken.CustomCurrency import com.tangem.domain.features.addCustomToken.CustomTokenFieldId -import com.tangem.network.api.tangemTech.CoinsResponse +import com.tangem.datasource.api.tangemTech.CoinsResponse import org.rekotlin.Action /** diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt index 2b56a47f90..3a48aa34a7 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt @@ -56,7 +56,7 @@ import com.tangem.domain.redux.domainStore import com.tangem.domain.redux.extensions.dispatchOnMain import com.tangem.domain.redux.global.DomainGlobalAction import com.tangem.domain.redux.global.DomainGlobalState -import com.tangem.network.api.tangemTech.CoinsResponse +import com.tangem.datasource.api.tangemTech.CoinsResponse import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt index 6dde5b01c6..978232de57 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt @@ -37,7 +37,7 @@ import com.tangem.domain.features.addCustomToken.TokenDerivationPathField import com.tangem.domain.features.addCustomToken.TokenField import com.tangem.domain.redux.DomainState import com.tangem.domain.redux.state.StringActionStateConverter -import com.tangem.network.api.tangemTech.CoinsResponse +import com.tangem.datasource.api.tangemTech.CoinsResponse import org.rekotlin.Action import org.rekotlin.StateType diff --git a/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalHub.kt b/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalHub.kt index d80b0bab73..a0d0cb833b 100644 --- a/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalHub.kt +++ b/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalHub.kt @@ -5,7 +5,7 @@ import com.tangem.common.extensions.toHexString import com.tangem.domain.redux.BaseStoreHub import com.tangem.domain.redux.DomainState import com.tangem.domain.redux.ReStoreReducer -import com.tangem.network.common.CardPublicKeyHttpInterceptor +import com.tangem.datasource.api.common.CardPublicKeyHttpInterceptor import org.rekotlin.Action /** diff --git a/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalState.kt b/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalState.kt index b420816c55..a013b2128f 100644 --- a/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalState.kt +++ b/domain/src/main/java/com/tangem/domain/redux/global/DomainGlobalState.kt @@ -3,8 +3,8 @@ package com.tangem.domain.redux.global import com.tangem.domain.DomainDialog import com.tangem.domain.common.LogConfig import com.tangem.domain.common.ScanResponse -import com.tangem.network.api.paymentology.PaymentologyApiService -import com.tangem.network.api.tangemTech.TangemTechService +import com.tangem.datasource.api.paymentology.PaymentologyApiService +import com.tangem.datasource.api.tangemTech.TangemTechService /** [REDACTED_AUTHOR] @@ -19,6 +19,8 @@ data class DomainGlobalState( ) data class NetworkServices( - val tangemTechService: TangemTechService = TangemTechService(LogConfig.network.tangemTechService), - val paymentologyService: PaymentologyApiService = PaymentologyApiService(LogConfig.network.paymentologyApiService), + val tangemTechService: TangemTechService = TangemTechService( + LogConfig.network.tangemTechService), + val paymentologyService: PaymentologyApiService = PaymentologyApiService( + LogConfig.network.paymentologyApiService), ) diff --git a/network/.gitignore b/features/swap/data/.gitignore similarity index 100% rename from network/.gitignore rename to features/swap/data/.gitignore diff --git a/features/swap/data/build.gradle.kts b/features/swap/data/build.gradle.kts new file mode 100644 index 0000000000..298948e089 --- /dev/null +++ b/features/swap/data/build.gradle.kts @@ -0,0 +1,37 @@ +plugins { + id("com.android.library") + kotlin("android") + kotlin("kapt") + id("com.google.dagger.hilt.android") +} + +android { + + defaultConfig { + compileSdk = AppConfig.compileSdkVersion + minSdk = AppConfig.minSdkVersion + targetSdk = AppConfig.targetSdkVersion + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + isCoreLibraryDesugaringEnabled = false + } +} + +dependencies { + + /** Project*/ + implementation(project(":core:datasource")) + implementation(project(":core:utils")) + implementation(project(":features:swap:domain")) + + /** DI */ + implementation(Library.hilt) + kapt(Library.hiltKapt) +} \ No newline at end of file diff --git a/features/swap/data/src/main/AndroidManifest.xml b/features/swap/data/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..5981b0aeee --- /dev/null +++ b/features/swap/data/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file 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 new file mode 100644 index 0000000000..2095876a1b --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt @@ -0,0 +1,82 @@ +package com.tangem.feature.swap + +import com.tangem.datasource.api.oneinch.OneInchApi +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.feature.swap.converters.ApproveConverter +import com.tangem.feature.swap.converters.QuotesConverter +import com.tangem.feature.swap.converters.SwapConverter +import com.tangem.feature.swap.converters.TokensConverter +import com.tangem.feature.swap.domain.SwapRepository +import com.tangem.feature.swap.domain.models.ApproveModel +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class SwapRepositoryImpl @Inject constructor( + private val tangemTechApi: TangemTechApi, + private val oneInchApi: OneInchApi, + private val tokensConverter: TokensConverter, + private val quotesConverter: QuotesConverter, + private val swapConverter: SwapConverter, + private val approveConverter: ApproveConverter, + private val coroutineDispatcher: CoroutineDispatcherProvider, +) : SwapRepository { + + override suspend fun getExchangeableTokens(networkId: String): List { + return withContext(coroutineDispatcher.io) { + tokensConverter.convertList(tangemTechApi.coins(exchangeable = true, networkIds = networkId).coins) + } + } + + override suspend fun findBestQuote(fromTokenAddress: String, toTokenAddress: String, amount: String): QuoteModel { + return withContext(coroutineDispatcher.io) { + quotesConverter.convert( + oneInchApi.quote( + fromTokenAddress = fromTokenAddress, + toTokenAddress = toTokenAddress, + amount = amount, + ), + ) + } + } + + override suspend fun addressForTrust(): String { + return withContext(coroutineDispatcher.io) { + oneInchApi.approveSpender().address + } + } + + override suspend fun dataToApprove(tokenAddress: String, amount: String): ApproveModel { + return withContext(coroutineDispatcher.io) { + approveConverter.convert(oneInchApi.approveTransaction(tokenAddress, amount)) + } + } + + override suspend fun checkTokensSpendAllowance(tokenAddress: String, walletAddress: String): String { + return withContext(coroutineDispatcher.io) { + oneInchApi.approveAllowance(tokenAddress, walletAddress).allowance + } + } + + override suspend fun prepareSwapTransaction( + fromTokenAddress: String, + toTokenAddress: String, + amount: String, + fromAddress: String, + slippage: Int, + ) { + return withContext(coroutineDispatcher.io) { + swapConverter.convert( + oneInchApi.swap( + fromTokenAddress = fromTokenAddress, + toTokenAddress = toTokenAddress, + amount = amount, + fromAddress = fromAddress, + slippage = slippage, + ), + ) + } + } +} \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ApproveConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ApproveConverter.kt new file mode 100644 index 0000000000..4d3574869d --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ApproveConverter.kt @@ -0,0 +1,17 @@ +package com.tangem.feature.swap.converters + +import com.tangem.datasource.api.oneinch.models.ApproveCalldataResponse +import com.tangem.feature.swap.domain.models.ApproveModel +import com.tangem.utils.converter.Converter +import javax.inject.Inject + +class ApproveConverter @Inject constructor() : Converter { + + override fun convert(value: ApproveCalldataResponse): ApproveModel { + return ApproveModel( + data = value.data, + gasPrice = value.gasPrice, + toAddress = value.toAddress, + ) + } +} \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt new file mode 100644 index 0000000000..52723c6596 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt @@ -0,0 +1,16 @@ +package com.tangem.feature.swap.converters + +import com.tangem.datasource.api.oneinch.models.QuoteResponse +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.utils.converter.Converter + +class QuotesConverter : Converter { + + override fun convert(value: QuoteResponse): QuoteModel { + return QuoteModel( + fromTokenAmount = value.fromTokenAmount, + toTokenAmount = value.toTokenAmount, + estimatedGas = value.estimatedGas, + ) + } +} \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SwapConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SwapConverter.kt new file mode 100644 index 0000000000..244ae4f2a0 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SwapConverter.kt @@ -0,0 +1,24 @@ +package com.tangem.feature.swap.converters + +import com.tangem.datasource.api.oneinch.models.SwapResponse +import com.tangem.feature.swap.domain.models.SwapTransactionModel +import com.tangem.utils.converter.Converter +import javax.inject.Inject + +class SwapConverter @Inject constructor() : Converter { + + override fun convert(value: SwapResponse): SwapTransactionModel { + return SwapTransactionModel( + fromTokenAddress = value.fromToken.address, + toTokenAddress = value.toToken.address, + toTokenAmount = value.fromTokenAmount, + fromTokenAmount = value.toTokenAmount, + fromWalletAddress = value.transaction.fromAddress, + toWalletAddress = value.transaction.toAddress, + data = value.transaction.data, + value = value.transaction.value, + gasPrice = value.transaction.gasPrice, + gas = value.transaction.gas, + ) + } +} \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/TokensConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/TokensConverter.kt new file mode 100644 index 0000000000..c5414d666c --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/TokensConverter.kt @@ -0,0 +1,32 @@ +package com.tangem.feature.swap.converters + +import com.tangem.datasource.api.tangemTech.CoinsResponse +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.utils.converter.Converter +import javax.inject.Inject + +class TokensConverter @Inject constructor() : Converter { + + override fun convert(value: CoinsResponse.Coin): Currency { + val network = value.networks.first() + return if (network.contractAddress != null && network.decimalCount != null) { + Currency.NonNativeToken( + id = value.id, + name = value.name, + symbol = value.symbol, + networkId = network.networkId, + contractAddress = network.contractAddress!!, + decimalCount = network.decimalCount!!.intValueExact(), + logoUrl = "",//todo add logo + ) + } else { + Currency.NativeToken( + id = value.id, + name = value.name, + symbol = value.symbol, + networkId = network.networkId, + logoUrl = "", //todo add logo + ) + } + } +} \ No newline at end of file diff --git a/features/swap/domain/.gitignore b/features/swap/domain/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/swap/domain/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/swap/domain/build.gradle.kts b/features/swap/domain/build.gradle.kts new file mode 100644 index 0000000000..e8259cee84 --- /dev/null +++ b/features/swap/domain/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("java-library") + id("org.jetbrains.kotlin.jvm") +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} \ No newline at end of file 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 new file mode 100644 index 0000000000..eebb325e5e --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt @@ -0,0 +1,4 @@ +package com.tangem.feature.swap.domain + +interface SwapInteractor { +} \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt new file mode 100644 index 0000000000..963f87bfdb --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt @@ -0,0 +1,52 @@ +package com.tangem.feature.swap.domain + +import com.tangem.feature.swap.domain.models.ApproveModel +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.QuoteModel + +interface SwapRepository { + + suspend fun getExchangeableTokens(networkId: String): List + + suspend fun findBestQuote( + fromTokenAddress: String, + toTokenAddress: String, + amount: String, + ): QuoteModel + + /** + * Returns address of 1inch router that must be trusted + * + * @return address + */ + suspend fun addressForTrust(): String + + /** + * Generate "data" for calling contract in order to allow 1inch spend funds + * + * @param tokenAddress token you want to exchange + * @param amount number of tokens is allowed. By default infinite + */ + suspend fun dataToApprove( + tokenAddress: String, + amount: String, + ): ApproveModel + + /** + * Get the number of tokens that the 1inch router is allowed to spend + * + * @param tokenAddress Token address you want to exchange + * @param walletAddress address for which you want to check + * + * @return amount of tokens allowed to spend + */ + suspend fun checkTokensSpendAllowance(tokenAddress: String, walletAddress: String): String + + suspend fun prepareSwapTransaction( + fromTokenAddress: String, + toTokenAddress: String, + amount: String, + fromAddress: String, + slippage: Int, + ) +} \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ApproveModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ApproveModel.kt new file mode 100644 index 0000000000..2fce5634f9 --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ApproveModel.kt @@ -0,0 +1,14 @@ +package com.tangem.feature.swap.domain.models + +/** + * Approve model + * + * @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 + */ +data class ApproveModel( + val data: String, + val gasPrice: String, + val toAddress: String, +) \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/Currency.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/Currency.kt new file mode 100644 index 0000000000..05fe0cad3b --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/Currency.kt @@ -0,0 +1,28 @@ +package com.tangem.feature.swap.domain.models + +sealed class Currency( + open val id: String, + open val name: String, + open val symbol: String, + open val networkId: String, + open val logoUrl: String, +) { + + data class NativeToken( + override val id: String, + override val name: String, + override val symbol: String, + override val networkId: String, + override val logoUrl: String, + ) : Currency(id, name, symbol, networkId, logoUrl) + + data class NonNativeToken( + override val id: String, + override val name: String, + override val symbol: String, + override val networkId: String, + override val logoUrl: String, + val contractAddress: String, + val decimalCount: Int, + ) : Currency(id, name, symbol, networkId, logoUrl) +} \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/QuoteModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/QuoteModel.kt new file mode 100644 index 0000000000..e71378fd22 --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/QuoteModel.kt @@ -0,0 +1,7 @@ +package com.tangem.feature.swap.domain.models + +data class QuoteModel( + val fromTokenAmount: String, + val toTokenAmount: String, + val estimatedGas: Int +) \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapTransactionModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapTransactionModel.kt new file mode 100644 index 0000000000..f36d74eb61 --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapTransactionModel.kt @@ -0,0 +1,29 @@ +package com.tangem.feature.swap.domain.models + +/** + * Swap transaction model + * + * @property fromTokenAddress token from which want to convert + * @property toTokenAddress token to want to convert + * @property toTokenAmount amount "target" token + * @property fromTokenAmount amount "initial" token + * @property fromWalletAddress wallet from address (transactions will be sent from this address) + * @property toWalletAddress 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 Swap transaction model + */ +data class SwapTransactionModel( + val fromTokenAddress: String, + val toTokenAddress: String, + val toTokenAmount: String, + val fromTokenAmount: String, + val fromWalletAddress: String, + val toWalletAddress: String, + val data: String, + val value: String, + val gasPrice: String, + val gas: String, +) \ No newline at end of file diff --git a/features/swap/presentation/.gitignore b/features/swap/presentation/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/swap/presentation/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/swap/presentation/build.gradle.kts b/features/swap/presentation/build.gradle.kts new file mode 100644 index 0000000000..8eac586d41 --- /dev/null +++ b/features/swap/presentation/build.gradle.kts @@ -0,0 +1,59 @@ +plugins { + id("com.android.library") + kotlin("android") + kotlin("kapt") + id("com.google.dagger.hilt.android") +} + +android { + + defaultConfig { + compileSdk = AppConfig.compileSdkVersion + minSdk = AppConfig.minSdkVersion + targetSdk = AppConfig.targetSdkVersion + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + isCoreLibraryDesugaringEnabled = false + } + + buildFeatures { + compose = true + } + + composeOptions { + kotlinCompilerExtensionVersion = Versions.compose + } +} + +dependencies { + /** Core modules */ + implementation(project(":core:utils")) + implementation(project(":core:ui")) + + /** AndroidX */ + implementation(AndroidX.appCompat) + implementation(AndroidX.fragmentKtx) + implementation(AndroidX.lifecycleViewModelKtx) + + /** Compose */ + implementation(Compose.foundation) + implementation(Compose.material) + implementation(Compose.uiTooling) + + /** Domain */ + implementation(project(":features:swap:domain")) + + /** Other libraries */ + implementation(Library.composeShimmer) + + /** DI */ + implementation(Library.hilt) + kapt(Library.hiltKapt) +} \ No newline at end of file diff --git a/features/swap/presentation/src/main/AndroidManifest.xml b/features/swap/presentation/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..927ad53a71 --- /dev/null +++ b/features/swap/presentation/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/network/build.gradle.kts b/network/build.gradle.kts deleted file mode 100644 index 0c82757e05..0000000000 --- a/network/build.gradle.kts +++ /dev/null @@ -1,26 +0,0 @@ -plugins { - id("java-library") - id("org.jetbrains.kotlin.jvm") -} - -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} - -dependencies { - implementation(project(":common")) - - /** Tangem libraries */ - implementation(Tangem.cardCore) - - /** Other libraries */ - implementation(Library.retrofit) - implementation(Library.retrofitMoshiConverter) - implementation(Library.moshi) - implementation(Library.moshiKotlin) - implementation(Library.okHttp) - implementation(Library.okHttpLogging) - implementation(Library.timber) - implementation(Library.coroutine) -} \ No newline at end of file diff --git a/network/src/main/java/com/tangem/network/common/NetworError.kt b/network/src/main/java/com/tangem/network/common/NetworError.kt deleted file mode 100644 index dfe852ecc9..0000000000 --- a/network/src/main/java/com/tangem/network/common/NetworError.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.network.common - -import com.tangem.common.module.ModuleError -import com.tangem.common.module.ModuleErrorCode -import com.tangem.common.module.ModuleMessage - -/** -[REDACTED_AUTHOR] - */ -sealed interface NetworkModuleMessage : ModuleMessage - -sealed class NetworkError( - subCode: Int, - override val message: String, - override val data: Any?, -) : NetworkModuleMessage, ModuleError() { - override val code: Int = ModuleErrorCode.NETWORK + subCode - - companion object { - // base code used for all error in the module - // const val CODE_ANY_OTHER = 100..199, 200..299 - } -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 013139ff41..028fd3f613 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,5 @@ include(":app") include(":domain") -include(":network") include(":common") // region Core modules @@ -19,4 +18,7 @@ include(":libs:auth") include(":features:referral:data") include(":features:referral:domain") include(":features:referral:presentation") +include(":features:swap:data") +include(":features:swap:domain") +include(":features:swap:presentation") // endregion Feature modules \ No newline at end of file