Updated on 2026-08-14

This commit is contained in:
Tangem 2022-12-12 16:29:05 +03:00
commit 1736106734
34 changed files with 425 additions and 76 deletions

View file

@ -11,6 +11,7 @@ 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.BigDecimalAdapter
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.domain.DomainLayer
import com.tangem.domain.common.LogConfig
@ -30,7 +31,6 @@ import com.tangem.tap.common.feedback.AdditionalFeedbackInfo
import com.tangem.tap.common.feedback.FeedbackManager
import com.tangem.tap.common.images.createCoilImageLoader
import com.tangem.tap.common.log.TangemLogCollector
import com.tangem.tap.common.moshi.BigDecimalAdapter
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.appReducer
import com.tangem.tap.common.redux.global.GlobalAction

View file

@ -88,7 +88,7 @@ fun FragmentActivity.getPreviousScreen(): AppScreen? {
fun FragmentActivity.addOnBackPressedDispatcher(
isEnabled: Boolean = true,
onBackPressed: VoidCallback
onBackPressed: VoidCallback,
): OnBackPressedCallback = (object : OnBackPressedCallback(isEnabled) {
override fun handleOnBackPressed() {
onBackPressed()

View file

@ -84,8 +84,8 @@ class UserWalletManagerImpl(
mainStore.dispatch(action)
}
override fun getWalletAddress(currency: Currency): String {
val blockchain = Blockchain.fromNetworkId(currency.networkId)
override fun getWalletAddress(networkId: String): String {
val blockchain = Blockchain.fromNetworkId(networkId)
val card = appStateHolder.getActualCard()
if (blockchain != null && card != null) {
val blockchainNetwork = BlockchainNetwork(blockchain, card)

View file

@ -63,6 +63,8 @@ dependencies {
implementation(Library.okHttp)
implementation(Library.okHttpLogging)
// kapt("com.squareup.moshi:moshi-kotlin-codegen:1.14.0")
/** Time */
implementation(Library.jodatime)
}

View file

@ -1,4 +1,4 @@
package com.tangem.tap.common.moshi
package com.tangem.datasource.api.common
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson

View file

@ -114,6 +114,7 @@ interface OneInchApi {
*
* @return [QuoteResponse]
*/
@GET("quote")
suspend fun quote(
@Query("fromTokenAddress") fromTokenAddress: String,
@Query("toTokenAddress") toTokenAddress: String,
@ -174,6 +175,7 @@ interface OneInchApi {
*
* @return [SwapResponse]
*/
@GET("swap")
suspend fun swap(
@Query("fromTokenAddress") fromTokenAddress: String,
@Query("toTokenAddress") toTokenAddress: String,

View file

@ -3,6 +3,7 @@ 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.common.BigDecimalAdapter
import com.tangem.datasource.api.oneinch.OneInchApi
import com.tangem.datasource.api.referral.ReferralApi
import com.tangem.datasource.api.tangemTech.TangemTechApi
@ -14,6 +15,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Singleton
@ -24,11 +26,12 @@ class NetworkModule {
@Provides
@Singleton
fun provideTangemTechApi(okHttpClient: OkHttpClient): TangemTechApi {
fun provideTangemTechApi(
okHttpClient: OkHttpClient,
converter: Converter.Factory,
): TangemTechApi {
return Retrofit.Builder()
.addConverterFactory(
MoshiConverterFactory.create(),
)
.addConverterFactory(converter)
.baseUrl(DEV_TANGEM_TECH_BASE_URL)
.client(okHttpClient)
.build()
@ -38,28 +41,26 @@ class NetworkModule {
@Provides
@Singleton
@OneInchEthereum
fun provideOneInchEthereumApi(): OneInchApi {
fun provideOneInchEthereumApi(converter: Converter.Factory): OneInchApi {
return Retrofit.Builder()
.addConverterFactory(
MoshiConverterFactory.create(),
)
.addConverterFactory(converter)
.baseUrl(ONE_INCH_ETHER_BASE_URL)
.client(OkHttpClient())
.client(
OkHttpClient.Builder()
.addInterceptor(
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY),
)
.build(),
)
.build()
.create(OneInchApi::class.java)
}
@Provides
@Singleton
fun provideReferralApi(okHttpClient: OkHttpClient): ReferralApi {
fun provideReferralApi(okHttpClient: OkHttpClient, converter: Converter.Factory): ReferralApi {
return Retrofit.Builder()
.addConverterFactory(
MoshiConverterFactory.create(
Moshi.Builder()
.addLast(KotlinJsonAdapterFactory())
.build(),
),
)
.addConverterFactory(converter)
.baseUrl(DEV_TANGEM_TECH_BASE_URL)
.client(okHttpClient)
.build()
@ -77,9 +78,20 @@ class NetworkModule {
.build()
}
@Provides
@Singleton
fun provideMoshiConverter(): Converter.Factory {
return MoshiConverterFactory.create(
Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(BigDecimalAdapter())
.build(),
)
}
private companion object {
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 = ""
const val ONE_INCH_ETHER_BASE_URL = "https://api.1inch.io/v5.0/1/"
}
}

View file

@ -7,8 +7,9 @@ import com.tangem.feature.referral.domain.ReferralRepository
import com.tangem.feature.referral.domain.models.ReferralData
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
import javax.inject.Inject
internal class ReferralRepositoryImpl(
internal class ReferralRepositoryImpl @Inject constructor(
private val referralApi: ReferralApi,
private val referralConverter: ReferralConverter,
private val coroutineDispatcher: CoroutineDispatcherProvider,

View file

@ -26,7 +26,7 @@ internal class ReferralInteractorImpl(
if (tokensForReferral.isNotEmpty()) {
val currency = tokensConverter.convert(tokensForReferral.first())
deriveOrAddTokens(currency)
val publicAddress = userWalletManager.getWalletAddress(currency)
val publicAddress = userWalletManager.getWalletAddress(currency.networkId)
return repository.startReferral(
walletId = userWalletManager.getWalletId(),
networkId = currency.networkId,

View file

@ -7,14 +7,15 @@ 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.feature.swap.domain.models.data.ApproveModel
import com.tangem.feature.swap.domain.models.data.Currency
import com.tangem.feature.swap.domain.models.data.QuoteModel
import com.tangem.feature.swap.domain.models.data.SwapDataModel
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
import javax.inject.Inject
class SwapRepositoryImpl @Inject constructor(
internal class SwapRepositoryImpl @Inject constructor(
private val tangemTechApi: TangemTechApi,
private val oneInchApi: OneInchApi,
private val tokensConverter: TokensConverter,
@ -64,16 +65,16 @@ class SwapRepositoryImpl @Inject constructor(
fromTokenAddress: String,
toTokenAddress: String,
amount: String,
fromAddress: String,
fromWalletAddress: String,
slippage: Int,
) {
): SwapDataModel {
return withContext(coroutineDispatcher.io) {
swapConverter.convert(
oneInchApi.swap(
fromTokenAddress = fromTokenAddress,
toTokenAddress = toTokenAddress,
amount = amount,
fromAddress = fromAddress,
fromAddress = fromWalletAddress,
slippage = slippage,
),
)

View file

@ -1,7 +1,7 @@
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.feature.swap.domain.models.data.ApproveModel
import com.tangem.utils.converter.Converter
import javax.inject.Inject

View file

@ -1,10 +1,11 @@
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.feature.swap.domain.models.data.QuoteModel
import com.tangem.utils.converter.Converter
import javax.inject.Inject
class QuotesConverter : Converter<QuoteResponse, QuoteModel> {
class QuotesConverter @Inject constructor(): Converter<QuoteResponse, QuoteModel> {
override fun convert(value: QuoteResponse): QuoteModel {
return QuoteModel(

View file

@ -1,24 +1,32 @@
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.datasource.api.oneinch.models.TransactionDto
import com.tangem.feature.swap.domain.models.data.SwapDataModel
import com.tangem.feature.swap.domain.models.data.TransactionModel
import com.tangem.utils.converter.Converter
import javax.inject.Inject
class SwapConverter @Inject constructor() : Converter<SwapResponse, SwapTransactionModel> {
class SwapConverter @Inject constructor() : Converter<SwapResponse, SwapDataModel> {
override fun convert(value: SwapResponse): SwapTransactionModel {
return SwapTransactionModel(
override fun convert(value: SwapResponse): SwapDataModel {
return SwapDataModel(
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,
transaction = convertTransaction(value.transaction),
)
}
private fun convertTransaction(transactionDto: TransactionDto): TransactionModel {
return TransactionModel(
fromWalletAddress = transactionDto.fromAddress,
toWalletAddress = transactionDto.toAddress,
data = transactionDto.data,
value = transactionDto.value,
gasPrice = transactionDto.gasPrice,
gas = transactionDto.gas,
)
}
}

View file

@ -1,7 +1,7 @@
package com.tangem.feature.swap.converters
import com.tangem.datasource.api.tangemTech.CoinsResponse
import com.tangem.feature.swap.domain.models.Currency
import com.tangem.feature.swap.domain.models.data.Currency
import com.tangem.utils.converter.Converter
import javax.inject.Inject
@ -17,7 +17,7 @@ class TokensConverter @Inject constructor() : Converter<CoinsResponse.Coin, Curr
networkId = network.networkId,
contractAddress = network.contractAddress!!,
decimalCount = network.decimalCount!!.intValueExact(),
logoUrl = "",//todo add logo
logoUrl = getSmallIconUrl(value.id),
)
} else {
Currency.NativeToken(
@ -25,8 +25,17 @@ class TokensConverter @Inject constructor() : Converter<CoinsResponse.Coin, Curr
name = value.name,
symbol = value.symbol,
networkId = network.networkId,
logoUrl = "", //todo add logo
logoUrl = getSmallIconUrl(value.id),
)
}
}
private fun getSmallIconUrl(coin: String): String {
return "$DEFAULT_IMAGE_HOST$SMALL_ICON_PATH/$coin.png"
}
companion object {
private const val DEFAULT_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/"
private const val SMALL_ICON_PATH = "small"
}
}

View file

@ -0,0 +1,44 @@
package com.tangem.feature.swap.di
import com.tangem.datasource.api.oneinch.OneInchApi
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.di.qualifiers.OneInchEthereum
import com.tangem.feature.swap.SwapRepositoryImpl
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.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
class SwapDataModule {
@Provides
@Singleton
fun provideSwapRepository(
tangemTechApi: TangemTechApi,
@OneInchEthereum oneInchApi: OneInchApi,
tokensConverter: TokensConverter,
quotesConverter: QuotesConverter,
swapConverter: SwapConverter,
approveConverter: ApproveConverter,
coroutineDispatcher: CoroutineDispatcherProvider,
): SwapRepository {
return SwapRepositoryImpl(
tangemTechApi = tangemTechApi,
oneInchApi = oneInchApi,
tokensConverter = tokensConverter,
quotesConverter = quotesConverter,
swapConverter = swapConverter,
approveConverter = approveConverter,
coroutineDispatcher = coroutineDispatcher,
)
}
}

View file

@ -1,6 +1,18 @@
plugins {
id("java-library")
id("org.jetbrains.kotlin.jvm")
kotlin("kapt")
}
dependencies {
/** Libs */
implementation(project(":libs:crypto"))
implementation(project(":core:utils"))
/** DI */
implementation(Library.hiltCore)
kapt(Library.hiltKapt)
}
java {

View file

@ -1,4 +1,20 @@
package com.tangem.feature.swap.domain
import com.tangem.feature.swap.domain.models.SwapResultModel
import com.tangem.feature.swap.domain.models.data.Currency
import com.tangem.feature.swap.domain.models.data.QuoteModel
interface SwapInteractor {
suspend fun getTokensToSwap(networkId: String): List<Currency>
suspend fun getTokenBalance(tokenId: String): String
suspend fun findBestQuote(
fromTokenAddress: String,
toTokenAddress: String,
amount: String,
): QuoteModel
suspend fun onSwap(): SwapResultModel
}

View file

@ -0,0 +1,79 @@
package com.tangem.feature.swap.domain
import com.tangem.feature.swap.domain.cache.SwapDataCache
import com.tangem.feature.swap.domain.models.SwapResultModel
import com.tangem.feature.swap.domain.models.data.Currency
import com.tangem.feature.swap.domain.models.data.QuoteModel
import com.tangem.feature.swap.domain.models.data.TransactionModel
import com.tangem.lib.crypto.UserWalletManager
import javax.inject.Inject
internal class SwapInteractorImpl @Inject constructor(
private val userWalletManager: UserWalletManager,
private val repository: SwapRepository,
private val cache: SwapDataCache,
) : SwapInteractor {
override suspend fun getTokensToSwap(networkId: String): List<Currency> {
val availableTokens = cache.getAvailableTokens(networkId)
return availableTokens.ifEmpty {
val tokens = repository.getExchangeableTokens(networkId)
cache.cacheAvailableToSwapTokens(networkId, tokens)
cache.cacheNetworkId(networkId)
tokens
}
}
override suspend fun getTokenBalance(tokenId: String): String {
TODO("Not yet implemented")
}
override suspend fun findBestQuote(fromTokenAddress: String, toTokenAddress: String, amount: String): QuoteModel {
val networkId = cache.getNetworkId()
val isAllowedToSpend = if (networkId.isNullOrEmpty()) {
false
} else {
repository.checkTokensSpendAllowance(fromTokenAddress, userWalletManager.getWalletAddress(networkId)) != "0"
}
repository.findBestQuote(fromTokenAddress, toTokenAddress, amount).let { quotes ->
cache.cacheSwapParams(quotes.copy(isAllowedToSpend = isAllowedToSpend), amount)
return quotes
}
}
override suspend fun onSwap(): SwapResultModel {
val quoteModel = cache.getLastQuote()
val amountToSwap = cache.getAmountToSwap()
val networkId = cache.getNetworkId()
if (quoteModel != null && amountToSwap != null && networkId != null) {
val swapData = repository.prepareSwapTransaction(
fromTokenAddress = quoteModel.fromTokenAmount,
toTokenAddress = quoteModel.toTokenAmount,
amount = amountToSwap,
slippage = DEFAULT_SLIPPAGE,
fromWalletAddress = getWalletAddress(networkId),
)
signTransactionData(swapData.transaction) //todo implement
return SwapResultModel.SwapSuccess(
quoteModel.fromTokenAmount,
quoteModel.toTokenAmount,
)
}
return SwapResultModel.SwapError(
0,
"",
)
}
private fun getWalletAddress(networkId: String): String {
return userWalletManager.getWalletAddress(networkId)
}
//todo implement after merge referral
private fun signTransactionData(transaction: TransactionModel) {
}
companion object {
private const val DEFAULT_SLIPPAGE = 2
}
}

View file

@ -1,8 +1,9 @@
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
import com.tangem.feature.swap.domain.models.data.ApproveModel
import com.tangem.feature.swap.domain.models.data.Currency
import com.tangem.feature.swap.domain.models.data.QuoteModel
import com.tangem.feature.swap.domain.models.data.SwapDataModel
interface SwapRepository {
@ -46,7 +47,7 @@ interface SwapRepository {
fromTokenAddress: String,
toTokenAddress: String,
amount: String,
fromAddress: String,
fromWalletAddress: String,
slippage: Int,
)
): SwapDataModel
}

View file

@ -0,0 +1,15 @@
package com.tangem.feature.swap.domain.cache
import com.tangem.feature.swap.domain.models.data.Currency
import com.tangem.feature.swap.domain.models.data.QuoteModel
interface SwapDataCache {
fun cacheNetworkId(networkId: String)
fun cacheSwapParams(quoteModel: QuoteModel, amount: String)
fun cacheAvailableToSwapTokens(networkId: String, tokens: List<Currency>)
fun getAvailableTokens(networkId: String): List<Currency>
fun getLastQuote(): QuoteModel?
fun getAmountToSwap(): String?
fun getNetworkId(): String?
}

View file

@ -0,0 +1,39 @@
package com.tangem.feature.swap.domain.cache
import com.tangem.feature.swap.domain.models.SwapDataHolder
import com.tangem.feature.swap.domain.models.data.Currency
import com.tangem.feature.swap.domain.models.data.QuoteModel
class SwapDataCacheImpl : SwapDataCache {
private var lastDataForSwap: SwapDataHolder = SwapDataHolder()
private val availableTokensForNetwork: MutableMap<String, List<Currency>> = mutableMapOf()
override fun cacheSwapParams(quoteModel: QuoteModel, amount: String) {
lastDataForSwap = lastDataForSwap.copy(quoteModel = quoteModel, amountToSwap = amount)
}
override fun cacheAvailableToSwapTokens(networkId: String, tokens: List<Currency>) {
availableTokensForNetwork[networkId] = tokens
}
override fun cacheNetworkId(networkId: String) {
lastDataForSwap = lastDataForSwap.copy(networkId = networkId)
}
override fun getNetworkId(): String? {
return lastDataForSwap.networkId
}
override fun getAvailableTokens(networkId: String): List<Currency> {
return availableTokensForNetwork.getOrElse(networkId) { emptyList() }
}
override fun getLastQuote(): QuoteModel? {
return lastDataForSwap.quoteModel
}
override fun getAmountToSwap(): String? {
return lastDataForSwap.amountToSwap
}
}

View file

@ -0,0 +1,30 @@
package com.tangem.feature.swap.domain.di
import com.tangem.feature.swap.domain.SwapInteractor
import com.tangem.feature.swap.domain.SwapInteractorImpl
import com.tangem.feature.swap.domain.SwapRepository
import com.tangem.feature.swap.domain.cache.SwapDataCacheImpl
import com.tangem.lib.crypto.UserWalletManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
class SwapDomainModule {
@Provides
@Singleton
fun provideSwapInteractor(
referralRepository: SwapRepository,
userWalletManager: UserWalletManager,
): SwapInteractor {
return SwapInteractorImpl(
userWalletManager = userWalletManager,
repository = referralRepository,
cache = SwapDataCacheImpl(),
)
}
}

View file

@ -1,7 +0,0 @@
package com.tangem.feature.swap.domain.models
data class QuoteModel(
val fromTokenAmount: String,
val toTokenAmount: String,
val estimatedGas: Int
)

View file

@ -0,0 +1,9 @@
package com.tangem.feature.swap.domain.models
import com.tangem.feature.swap.domain.models.data.QuoteModel
data class SwapDataHolder(
val quoteModel: QuoteModel? = null,
val amountToSwap: String? = null,
val networkId: String? = null,
)

View file

@ -0,0 +1,14 @@
package com.tangem.feature.swap.domain.models
sealed interface SwapResultModel {
data class SwapSuccess(
val fromTokenAmount: String,
val toTokenAmount: String,
) : SwapResultModel
data class SwapError(
val errorCode: Int,
val errorMessage: String,
) : SwapResultModel
}

View file

@ -1,4 +1,4 @@
package com.tangem.feature.swap.domain.models
package com.tangem.feature.swap.domain.models.data
/**
* Approve model

View file

@ -1,4 +1,4 @@
package com.tangem.feature.swap.domain.models
package com.tangem.feature.swap.domain.models.data
sealed class Currency(
open val id: String,

View file

@ -0,0 +1,8 @@
package com.tangem.feature.swap.domain.models.data
data class QuoteModel(
val fromTokenAmount: String,
val toTokenAmount: String,
val estimatedGas: Int,
val isAllowedToSpend: Boolean = false,
)

View file

@ -0,0 +1,17 @@
package com.tangem.feature.swap.domain.models.data
/**
* 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
*/
data class SwapDataModel(
val fromTokenAddress: String,
val toTokenAddress: String,
val toTokenAmount: String,
val fromTokenAmount: String,
val transaction: TransactionModel
)

View file

@ -1,25 +1,16 @@
package com.tangem.feature.swap.domain.models
package com.tangem.feature.swap.domain.models.data
/**
* Swap transaction model
* 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,
data class TransactionModel(
val fromWalletAddress: String,
val toWalletAddress: String,
val data: String,

View file

@ -49,6 +49,7 @@ dependencies {
/** Domain */
implementation(project(":features:swap:domain"))
implementation(project(":features:swap:data"))//todo remove, only for test
/** Other libraries */
implementation(Library.composeShimmer)

View file

@ -0,0 +1,29 @@
package com.tangem.feature.swap.presentation
import android.os.Bundle
import android.transition.TransitionInflater
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.WindowCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.tangem.feature.swap.viewmodels.SwapViewModel
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class SwapFragment : Fragment() {
private val viewModel by viewModels<SwapViewModel>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) }
viewModel
return ComposeView(inflater.context).apply {
setContent {
//todo add compose screen here
}
}
}
}

View file

@ -0,0 +1,15 @@
package com.tangem.feature.swap.viewmodels
import androidx.lifecycle.ViewModel
import com.tangem.feature.swap.domain.SwapInteractor
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
internal class SwapViewModel @Inject constructor(
private val referralInteractor: SwapInteractor,
private val dispatchers: CoroutineDispatcherProvider,
) : ViewModel() {
}

View file

@ -34,7 +34,7 @@ interface UserWalletManager {
/**
* Returns wallet public address for token
*
* @param currency for which find address
* @param networkId for currency
*/
fun getWalletAddress(currency: Currency): String
fun getWalletAddress(networkId: String): String
}