Updated on 2026-08-14
This commit is contained in:
parent
dbb8ab5d50
commit
611d980d5e
9 changed files with 54 additions and 157 deletions
|
|
@ -64,6 +64,12 @@ internal object TransactionDomainModule {
|
|||
return CreateTransactionUseCase(transactionRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideEstimateFeeUseCase(walletManagersFacade: WalletManagersFacade): EstimateFeeUseCase {
|
||||
return EstimateFeeUseCase(walletManagersFacade)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideIsFeeApproximateUseCase(feeRepository: FeeRepository): IsFeeApproximateUseCase {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.datasource.local.userwallet.UserWalletsStore
|
|||
import com.tangem.datasource.local.walletmanager.WalletManagersStore
|
||||
import com.tangem.domain.walletmanager.DefaultWalletManagersFacade
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -23,12 +24,14 @@ internal object WalletManagersFacadeModule {
|
|||
userWalletsStore: UserWalletsStore,
|
||||
assetLoader: AssetLoader,
|
||||
blockchainSDKFactory: BlockchainSDKFactory,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): WalletManagersFacade {
|
||||
return DefaultWalletManagersFacade(
|
||||
walletManagersStore = walletManagersStore,
|
||||
userWalletsStore = userWalletsStore,
|
||||
assetLoader = assetLoader,
|
||||
blockchainSDKFactory = blockchainSDKFactory,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,10 @@
|
|||
package com.tangem.tap.proxy
|
||||
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.tangem.Message
|
||||
import com.tangem.blockchain.blockchains.algorand.AlgorandTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.cosmos.CosmosTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||
import com.tangem.blockchain.blockchains.hedera.HederaTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.optimism.EthereumOptimisticRollupWalletManager
|
||||
import com.tangem.blockchain.blockchains.stellar.StellarMemo
|
||||
import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.ton.TonTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
|
|
@ -65,31 +56,6 @@ class TransactionManagerImpl(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun sendTransaction(
|
||||
txData: SwapTxData,
|
||||
isSwap: Boolean,
|
||||
derivationPath: String?,
|
||||
analyticsData: AnalyticsData,
|
||||
): SendTxResult {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(txData.networkId)) { "blockchain not found" }
|
||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||
walletManager.update()
|
||||
val amount = if (isSwap) {
|
||||
createAmountForSwap(txData.amountToSend, txData.currencyToSend, blockchain)
|
||||
} else {
|
||||
createAmount(txData.amountToSend, txData.currencyToSend, blockchain)
|
||||
}
|
||||
return sendTransactionInternal(
|
||||
walletManager = walletManager,
|
||||
amount = amount,
|
||||
blockchain = blockchain,
|
||||
feeAmount = txData.feeAmount,
|
||||
gasLimit = txData.gasLimit,
|
||||
destinationAddress = txData.destinationAddress,
|
||||
dataToSign = txData.dataToSign,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
private suspend fun sendTransactionInternal(
|
||||
walletManager: WalletManager,
|
||||
|
|
@ -125,39 +91,11 @@ class TransactionManagerImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getMemoExtras(networkId: String, memo: String?): TransactionExtras? {
|
||||
val blockchain = Blockchain.fromNetworkId(networkId)
|
||||
if (memo == null) return null
|
||||
return when (blockchain) {
|
||||
Blockchain.Stellar -> {
|
||||
val xlmMemo = if (memo.isNotEmpty() && memo.isDigitsOnly()) {
|
||||
StellarMemo.Id(memo.toBigInteger())
|
||||
} else {
|
||||
StellarMemo.Text(memo)
|
||||
}
|
||||
StellarTransactionExtras(xlmMemo)
|
||||
}
|
||||
Blockchain.Binance -> BinanceTransactionExtras(memo)
|
||||
Blockchain.XRP -> memo.toLongOrNull()?.let { XrpTransactionBuilder.XrpTransactionExtras(it) }
|
||||
Blockchain.Cosmos -> CosmosTransactionExtras(memo)
|
||||
Blockchain.TON -> TonTransactionExtras(memo)
|
||||
Blockchain.Hedera -> HederaTransactionExtras(memo)
|
||||
Blockchain.Algorand -> AlgorandTransactionExtras(memo)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateWalletManager(networkId: String, derivationPath: String?) {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
getActualWalletManager(blockchain, derivationPath).update()
|
||||
}
|
||||
|
||||
override fun calculateFee(networkId: String, gasPrice: String, estimatedGas: Int): BigDecimal {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
val gasPriceValue = requireNotNull(gasPrice.toLongOrNull()) { "gasprice should be Long" }
|
||||
return (gasPriceValue * estimatedGas).toBigDecimal().movePointLeft(blockchain.decimals())
|
||||
}
|
||||
|
||||
@Throws(IllegalStateException::class)
|
||||
override suspend fun getFee(
|
||||
networkId: String,
|
||||
|
|
@ -512,25 +450,6 @@ class TransactionManagerImpl(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createAmountForSwap(amount: BigDecimal, currency: Currency?, blockchain: Blockchain): Amount {
|
||||
return when (currency) {
|
||||
is Currency.NativeToken,
|
||||
null,
|
||||
-> {
|
||||
Amount(value = amount, blockchain = blockchain)
|
||||
}
|
||||
is Currency.NonNativeToken -> {
|
||||
// 1. when creates swap amount for NonNativeToken, amount should be ZERO
|
||||
// 2. Amount has .Coin type, as workaround to use destinationAddress in bsdk, not contractAddress
|
||||
Amount(
|
||||
currencySymbol = currency.symbol,
|
||||
value = BigDecimal.ZERO,
|
||||
decimals = currency.decimalCount,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertNonNativeToken(token: Currency.NonNativeToken): Token {
|
||||
return Token(
|
||||
name = token.name,
|
||||
|
|
|
|||
|
|
@ -36,20 +36,23 @@ import com.tangem.domain.walletmanager.utils.*
|
|||
import com.tangem.domain.walletmanager.utils.WalletManagerFactory
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import java.util.EnumSet
|
||||
|
||||
@Suppress("LargeClass", "TooManyFunctions", "LongParameterList")
|
||||
@Suppress("LargeClass", "TooManyFunctions")
|
||||
// FIXME: Move to its own module and make internal
|
||||
@Deprecated("Inject the WalletManagerFacade interface using DI instead")
|
||||
class DefaultWalletManagersFacade(
|
||||
private val walletManagersStore: WalletManagersStore,
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val assetLoader: AssetLoader,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
blockchainSDKFactory: BlockchainSDKFactory,
|
||||
) : WalletManagersFacade {
|
||||
|
||||
|
|
@ -467,7 +470,7 @@ class DefaultWalletManagersFacade(
|
|||
amount: Amount,
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): Result<TransactionFee>? {
|
||||
): Result<TransactionFee>? = withContext(dispatchers.io) {
|
||||
val blockchain = Blockchain.fromId(network.id.value)
|
||||
val walletManager = getOrCreateWalletManager(
|
||||
userWalletId = userWalletId,
|
||||
|
|
@ -477,7 +480,7 @@ class DefaultWalletManagersFacade(
|
|||
|
||||
val destination = estimationFeeAddressFactory.makeAddress(blockchain)
|
||||
|
||||
return (walletManager as? TransactionSender)?.estimateFee(
|
||||
(walletManager as? TransactionSender)?.estimateFee(
|
||||
amount = amount,
|
||||
destination = destination,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,10 +12,8 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
|||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
|
|
@ -23,7 +21,6 @@ import java.math.BigDecimal
|
|||
*/
|
||||
class EstimateFeeUseCase(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val dispatcher: CoroutineDispatcherProvider,
|
||||
) {
|
||||
suspend operator fun invoke(
|
||||
amount: BigDecimal,
|
||||
|
|
@ -43,7 +40,7 @@ class EstimateFeeUseCase(
|
|||
null -> GetFeeError.UnknownError.left()
|
||||
}
|
||||
emit(maybeFee)
|
||||
}.flowOn(dispatcher.io)
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertCryptoCurrencyToAmount(cryptoCurrency: CryptoCurrency, amount: BigDecimal) = Amount(
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class ValidateTransactionUseCase(
|
|||
@Suppress("LongParameterList")
|
||||
suspend operator fun invoke(
|
||||
amount: Amount,
|
||||
fee: Fee,
|
||||
fee: Fee?,
|
||||
memo: String?,
|
||||
destination: String,
|
||||
userWalletId: UserWalletId,
|
||||
|
|
|
|||
|
|
@ -24,13 +24,12 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.tokens.utils.convertToAmount
|
||||
import com.tangem.domain.transaction.TransactionRepository
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.domain.transaction.usecase.CreateTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.EstimateFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.transaction.usecase.ValidateTransactionUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
|
|
@ -46,7 +45,6 @@ import com.tangem.lib.crypto.TransactionManager
|
|||
import com.tangem.lib.crypto.UserWalletManager
|
||||
import com.tangem.lib.crypto.models.*
|
||||
import com.tangem.lib.crypto.models.transactions.SendTxResult
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import timber.log.Timber
|
||||
|
|
@ -63,24 +61,19 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
private val allowPermissionsHandler: AllowPermissionsHandler,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val sendTransactionUseCase: SendTransactionUseCase,
|
||||
private val createTransactionUseCase: CreateTransactionUseCase,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val dispatcher: CoroutineDispatcherProvider,
|
||||
private val swapTransactionRepository: SwapTransactionRepository,
|
||||
private val currencyChecksRepository: CurrencyChecksRepository,
|
||||
private val appCurrencyRepository: AppCurrencyRepository,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val initialToCurrencyResolver: InitialToCurrencyResolver,
|
||||
private val demoConfig: DemoConfig,
|
||||
private val transactionRepository: TransactionRepository,
|
||||
private val validateTransactionUseCase: ValidateTransactionUseCase,
|
||||
private val estimateFeeUseCase: EstimateFeeUseCase,
|
||||
) : SwapInteractor {
|
||||
|
||||
private val estimateFeeUseCase by lazy(LazyThreadSafetyMode.NONE) {
|
||||
EstimateFeeUseCase(walletManagersFacade, dispatcher)
|
||||
}
|
||||
|
||||
private val getSelectedAppCurrencyUseCase by lazy(LazyThreadSafetyMode.NONE) {
|
||||
GetSelectedAppCurrencyUseCase(appCurrencyRepository)
|
||||
}
|
||||
|
|
@ -475,34 +468,33 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
userWalletId: UserWalletId,
|
||||
minAdaValue: BigDecimal?,
|
||||
) {
|
||||
transactionRepository.validateTransaction(
|
||||
validateTransactionUseCase(
|
||||
amount = amount.value.convertToAmount(fromToken),
|
||||
fee = null,
|
||||
memo = null,
|
||||
destination = getTokenAddress(fromToken),
|
||||
userWalletId = userWalletId,
|
||||
network = fromToken.network,
|
||||
)
|
||||
.fold(
|
||||
onFailure = {
|
||||
addCardanoTransactionValidationError(
|
||||
warnings = warnings,
|
||||
error = it as? BlockchainSdkError.Cardano ?: return@fold,
|
||||
fromToken = fromToken,
|
||||
userWalletId = userWalletId,
|
||||
).fold(
|
||||
ifLeft = {
|
||||
addCardanoTransactionValidationError(
|
||||
warnings = warnings,
|
||||
error = it as? BlockchainSdkError.Cardano ?: return@fold,
|
||||
fromToken = fromToken,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
minAdaValue?.let {
|
||||
warnings.add(
|
||||
Warning.Cardano.MinAdaValueCharged(
|
||||
tokenName = fromToken.name,
|
||||
minAdaValue = minAdaValue.parseBigDecimal(fromToken.decimals),
|
||||
),
|
||||
)
|
||||
},
|
||||
onSuccess = {
|
||||
minAdaValue?.let {
|
||||
warnings.add(
|
||||
Warning.Cardano.MinAdaValueCharged(
|
||||
tokenName = fromToken.name,
|
||||
minAdaValue = minAdaValue.parseBigDecimal(fromToken.decimals),
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun addCardanoTransactionValidationError(
|
||||
|
|
@ -706,28 +698,27 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
val exchangeDataCex =
|
||||
exchangeData.transaction as? ExpressTransactionModel.CEX ?: return SwapTransactionState.UnknownError
|
||||
|
||||
val txExtras = transactionManager.getMemoExtras(
|
||||
currencyToSend.currency.network.backendId,
|
||||
exchangeDataCex.txExtraId,
|
||||
)
|
||||
val cardId = getSelectedWallet()?.scanResponse?.card?.cardId ?: return SwapTransactionState.UnknownError
|
||||
if (txExtras == null && exchangeDataCex.txExtraId != null && !demoConfig.isDemoCardId(cardId)) {
|
||||
return SwapTransactionState.UnknownError
|
||||
}
|
||||
if (demoConfig.isDemoCardId(cardId)) return SwapTransactionState.UnknownError
|
||||
|
||||
val txData = createTransactionUseCase(
|
||||
amount = amount.value.convertToAmount(currencyToSend.currency),
|
||||
fee = getFeeForTransaction(
|
||||
fee = txFee,
|
||||
blockchain = Blockchain.fromId(currencyToSend.currency.network.id.value),
|
||||
),
|
||||
memo = null,
|
||||
memo = exchangeDataCex.txExtraId,
|
||||
destination = exchangeDataCex.txTo,
|
||||
userWalletId = userWalletId,
|
||||
network = currencyToSend.currency.network,
|
||||
).getOrElse {
|
||||
Timber.e(it)
|
||||
return SwapTransactionState.UnknownError
|
||||
}.copy(extras = txExtras)
|
||||
}
|
||||
|
||||
if (txData.extras == null && exchangeDataCex.txExtraId != null) {
|
||||
return SwapTransactionState.UnknownError
|
||||
}
|
||||
|
||||
val result = sendTransactionUseCase(
|
||||
txData = txData,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ import com.tangem.domain.tokens.repository.NetworksRepository
|
|||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.transaction.TransactionRepository
|
||||
import com.tangem.domain.transaction.usecase.CreateTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.EstimateFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.ValidateTransactionUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
|
|
@ -46,11 +48,10 @@ class SwapDomainModule {
|
|||
swapTransactionRepository: SwapTransactionRepository,
|
||||
appCurrencyRepository: AppCurrencyRepository,
|
||||
currencyChecksRepository: CurrencyChecksRepository,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
coroutineDispatcherProvider: CoroutineDispatcherProvider,
|
||||
initialToCurrencyResolver: InitialToCurrencyResolver,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
transactionRepository: TransactionRepository,
|
||||
validateTransactionUseCase: ValidateTransactionUseCase,
|
||||
estimateFeeUseCase: EstimateFeeUseCase,
|
||||
): SwapInteractor {
|
||||
return SwapInteractorImpl(
|
||||
transactionManager = transactionManager,
|
||||
|
|
@ -62,15 +63,14 @@ class SwapDomainModule {
|
|||
sendTransactionUseCase = sendTransactionUseCase,
|
||||
createTransactionUseCase = createTransactionUseCase,
|
||||
quotesRepository = quotesRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
dispatcher = coroutineDispatcherProvider,
|
||||
swapTransactionRepository = swapTransactionRepository,
|
||||
appCurrencyRepository = appCurrencyRepository,
|
||||
currencyChecksRepository = currencyChecksRepository,
|
||||
currenciesRepository = currenciesRepository,
|
||||
initialToCurrencyResolver = initialToCurrencyResolver,
|
||||
demoConfig = DemoConfig(),
|
||||
transactionRepository = transactionRepository,
|
||||
validateTransactionUseCase = validateTransactionUseCase,
|
||||
estimateFeeUseCase = estimateFeeUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.lib.crypto
|
||||
|
||||
import com.tangem.blockchain.common.TransactionExtras
|
||||
import com.tangem.lib.crypto.models.*
|
||||
import com.tangem.lib.crypto.models.transactions.SendTxResult
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -14,22 +13,6 @@ interface TransactionManager {
|
|||
analyticsData: AnalyticsData,
|
||||
): SendTxResult
|
||||
|
||||
/**
|
||||
* Send transaction
|
||||
*
|
||||
* @param txData data to build a tx
|
||||
* @param derivationPath for select right walletManager
|
||||
* @param analyticsData data for send analytics event
|
||||
* @return result of transaction
|
||||
*/
|
||||
@Throws(IllegalStateException::class)
|
||||
suspend fun sendTransaction(
|
||||
txData: SwapTxData,
|
||||
isSwap: Boolean,
|
||||
derivationPath: String?,
|
||||
analyticsData: AnalyticsData,
|
||||
): SendTxResult
|
||||
|
||||
/**
|
||||
* Get fee
|
||||
*
|
||||
|
|
@ -57,8 +40,6 @@ interface TransactionManager {
|
|||
@Throws(IllegalStateException::class)
|
||||
suspend fun updateWalletManager(networkId: String, derivationPath: String?)
|
||||
|
||||
fun calculateFee(networkId: String, gasPrice: String, estimatedGas: Int): BigDecimal
|
||||
|
||||
/**
|
||||
* In app blockchain id, actual in blockchain sdk, not the same as networkId
|
||||
*
|
||||
|
|
@ -69,7 +50,4 @@ interface TransactionManager {
|
|||
|
||||
@Throws(IllegalStateException::class)
|
||||
fun getExplorerTransactionLink(networkId: String, txAddress: String): String
|
||||
|
||||
// TODO: move to another place to use as in Send feature
|
||||
fun getMemoExtras(networkId: String, memo: String?): TransactionExtras?
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue