Updated on 2026-08-14
This commit is contained in:
commit
bc84d8f5f8
579 changed files with 13604 additions and 3422 deletions
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -7,4 +8,6 @@ dependencies {
|
|||
api(deps.kotlin.coroutines)
|
||||
api(deps.arrow.core)
|
||||
api(deps.arrow.fx)
|
||||
|
||||
implementation(deps.kotlin.serialization)
|
||||
}
|
||||
|
|
@ -96,4 +96,15 @@ sealed class Lce<out E : Any, out C : Any> {
|
|||
ifContent = ::identity,
|
||||
ifError = { null },
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns the error of this [Lce] if it's a [Lce.Error], `null` otherwise.
|
||||
*
|
||||
* @return The error of this [Lce] or `null`.
|
||||
*/
|
||||
fun errorOrNull(): E? = fold(
|
||||
ifLoading = { null },
|
||||
ifContent = { null },
|
||||
ifError = ::identity,
|
||||
)
|
||||
}
|
||||
|
|
@ -2,8 +2,10 @@ package com.tangem.domain.core.lce
|
|||
|
||||
import arrow.atomic.Atomic
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.RaiseDSL
|
||||
import arrow.core.raise.recover
|
||||
import com.tangem.domain.core.utils.lceContent
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
|
||||
|
|
@ -18,18 +20,55 @@ class LceRaise<E : Any> @PublishedApi internal constructor(
|
|||
private val raise: Raise<Lce<E, Nothing>>,
|
||||
) : Raise<Lce<E, Nothing>> by raise {
|
||||
|
||||
/**
|
||||
* An [Atomic] boolean flag indicating whether a loading operation is in progress.
|
||||
*/
|
||||
val isLoading: Atomic<Boolean> = Atomic(false)
|
||||
|
||||
/**
|
||||
* Helper function to raise an [Lce.Error] state with the given error object.
|
||||
* */
|
||||
@RaiseDSL
|
||||
@JvmName(name = "raiseError")
|
||||
fun raise(r: E): Nothing = raise(r = r.lceError())
|
||||
|
||||
/**
|
||||
* Helper function to raise an [Lce.Loading] state.
|
||||
*/
|
||||
@RaiseDSL
|
||||
fun raiseLoading(): Nothing = raise(r = lceLoading())
|
||||
|
||||
/**
|
||||
* Execute the [Raise] context function resulting in [C] or any _logical error_ of type [OtherError],
|
||||
* and transform any raised [OtherError] into [E], which is raised to the outer [Raise].
|
||||
*
|
||||
* @see arrow.core.raise.withError
|
||||
* */
|
||||
@RaiseDSL
|
||||
@OptIn(ExperimentalTypeInference::class)
|
||||
inline fun <OtherError : Any, C : Any> withError(
|
||||
transform: (OtherError) -> E,
|
||||
@BuilderInference block: LceRaise<OtherError>.() -> C,
|
||||
): C = recover(
|
||||
block = { block(LceRaise(raise = this@recover)) },
|
||||
recover = { error ->
|
||||
error.fold<Nothing>(
|
||||
ifLoading = { raiseLoading() },
|
||||
ifError = { raise(transform(it)) },
|
||||
ifContent = { it },
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
* Binds the content of this [Lce] instance and handles its state.
|
||||
* If this is a [Lce.Loading] state, sets the [isLoading] flag to true and calls the [ifLoading] function.
|
||||
* If this is a [Lce.Content] state, returns the content.
|
||||
* If this is a [Lce.Error] state, raises the error.
|
||||
*
|
||||
* @param ifLoading The function to call if this is a [Lce.Loading] state.
|
||||
* By default, it raises a new [Lce.Loading] state.
|
||||
* @return The content of this [Lce] instance.
|
||||
*/
|
||||
@RaiseDSL
|
||||
fun <C : Any> Lce<E, C>.bind(): C = when (this) {
|
||||
is Lce.Loading -> {
|
||||
isLoading.set(true)
|
||||
|
|
@ -48,6 +87,7 @@ class LceRaise<E : Any> @PublishedApi internal constructor(
|
|||
*
|
||||
* @return The content of this [Lce] instance.
|
||||
*/
|
||||
@RaiseDSL
|
||||
fun <C : Any> Lce<E, C>.bindOrNull(): C? = when (this) {
|
||||
is Lce.Loading -> {
|
||||
isLoading.set(true)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.domain.core.serialization
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal object BigDecimalSerializer : KSerializer<BigDecimal> {
|
||||
|
||||
override val descriptor = PrimitiveSerialDescriptor(serialName = "BigDecimal", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: BigDecimal) {
|
||||
encoder.encodeString(value.toString())
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): BigDecimal {
|
||||
return BigDecimal(decoder.decodeString())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.domain.core.serialization
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.math.BigDecimal
|
||||
|
||||
typealias SerializedBigDecimal = @Serializable(with = BigDecimalSerializer::class) BigDecimal
|
||||
|
|
@ -19,6 +19,6 @@ object NetworkLogConfig {
|
|||
}
|
||||
|
||||
object AnalyticsHandlersLogConfig {
|
||||
const val firebase: Boolean = false
|
||||
val firebase: Boolean = BuildConfig.LOG_ENABLED
|
||||
val amplitude: Boolean = BuildConfig.LOG_ENABLED
|
||||
}
|
||||
|
|
@ -11,5 +11,5 @@ interface ReduxStateHolder {
|
|||
|
||||
suspend fun onUserWalletSelected(userWallet: UserWallet)
|
||||
|
||||
fun sendFeedbackEmail()
|
||||
fun dispatchDialogShow(dialog: StateDialog)
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.domain.redux
|
||||
|
||||
interface StateDialog {
|
||||
|
||||
data class ScanFailsDialog(val source: ScanFailsSource, val onTryAgain: (() -> Unit)? = null) : StateDialog
|
||||
|
||||
enum class ScanFailsSource {
|
||||
MAIN, SIGN_IN, SETTINGS, INTRO;
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ 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(
|
||||
|
|
@ -470,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,
|
||||
|
|
@ -480,7 +480,7 @@ class DefaultWalletManagersFacade(
|
|||
|
||||
val destination = estimationFeeAddressFactory.makeAddress(blockchain)
|
||||
|
||||
return (walletManager as? TransactionSender)?.estimateFee(
|
||||
(walletManager as? TransactionSender)?.estimateFee(
|
||||
amount = amount,
|
||||
destination = destination,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.domain.settings
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
|
||||
class DelayPermissionRequestUseCase(
|
||||
private val repository: PermissionRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(permission: String): Either<Throwable, Unit> = Either.catch {
|
||||
repository.delayPermissionAsking(permission)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.settings
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
|
||||
class IsFirstTimeAskingPermissionUseCase(private val repository: PermissionRepository) {
|
||||
|
||||
suspend operator fun invoke(permission: String): Either<Throwable, Boolean> = Either.catch {
|
||||
repository.isFirstTimeAskingPermission(permission)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.domain.settings
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
|
||||
class NeverRequestPermissionUseCase(
|
||||
private val repository: PermissionRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(permission: String): Either<Throwable, Unit> = Either.catch {
|
||||
repository.neverAskPermission(permission)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.settings
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
|
||||
class SetFirstTimeAskingPermissionUseCase(private val repository: PermissionRepository) {
|
||||
|
||||
suspend operator fun invoke(permission: String): Either<Throwable, Unit> = Either.catch {
|
||||
repository.setFirstTimeAskingPermission(permission, false)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.domain.settings
|
||||
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
|
||||
class ShouldAskPermissionUseCase(
|
||||
private val repository: PermissionRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(permission: String): Boolean = repository.shouldAskPermission(permission)
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.settings
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
|
||||
class ShouldInitiallyAskPermissionUseCase(private val repository: PermissionRepository) {
|
||||
|
||||
suspend operator fun invoke(permission: String): Either<Throwable, Boolean> = Either.catch {
|
||||
repository.shouldInitiallyShowPermissionScreen(permission)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.domain.settings.repositories
|
||||
|
||||
interface PermissionRepository {
|
||||
|
||||
/**
|
||||
* Return true if should display screen ONCE asking to allow [permission].
|
||||
* False otherwise or screen already was displayed
|
||||
*/
|
||||
suspend fun shouldInitiallyShowPermissionScreen(permission: String): Boolean
|
||||
|
||||
/**
|
||||
* Indicates which time [permission] was asked via platform dialog.
|
||||
* NOTE: Use this method to indicate either reroute to settings or display platform dialog.
|
||||
*/
|
||||
suspend fun isFirstTimeAskingPermission(permission: String): Boolean
|
||||
|
||||
/**
|
||||
* Sets value indicating that [permission] was asked via platform dialog.
|
||||
* NOTE: Use this method to indicate either reroute to settings or display platform dialog.
|
||||
*/
|
||||
suspend fun setFirstTimeAskingPermission(permission: String, value: Boolean)
|
||||
|
||||
/**
|
||||
* Is clear to ask [permission].
|
||||
* User could already granted or permanently denied permission
|
||||
* Or there is an active delay before next request
|
||||
*/
|
||||
suspend fun shouldAskPermission(permission: String): Boolean
|
||||
|
||||
/**
|
||||
* Permanently deny [permission] and never request again
|
||||
*/
|
||||
suspend fun neverAskPermission(permission: String)
|
||||
|
||||
/**
|
||||
* Delay next [permission] request for some time or active sessions
|
||||
*/
|
||||
suspend fun delayPermissionAsking(permission: String)
|
||||
}
|
||||
|
|
@ -1,9 +1,20 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.domain.staking"
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.arrow.core)
|
||||
api(projects.domain.staking.models)
|
||||
|
||||
api(projects.domain.core)
|
||||
implementation(deps.kotlin.serialization)
|
||||
|
||||
implementation(projects.domain.tokens.models)
|
||||
}
|
||||
1
domain/staking/models/.gitignore
vendored
Normal file
1
domain/staking/models/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
12
domain/staking/models/build.gradle.kts
Normal file
12
domain/staking/models/build.gradle.kts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.domain.core)
|
||||
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(deps.jodatime)
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.tangem.domain.staking.model
|
||||
|
||||
enum class NetworkType {
|
||||
AVALANCHE_C,
|
||||
AVALANCHE_ATOMIC,
|
||||
AVALANCHE_P,
|
||||
ARBITRUM,
|
||||
BINANCE,
|
||||
CELO,
|
||||
ETHEREUM,
|
||||
ETHEREUM_GOERLI,
|
||||
ETHEREUM_HOLESKY,
|
||||
FANTOM,
|
||||
HARMONY,
|
||||
OPTIMISM,
|
||||
POLYGON,
|
||||
GNOSIS,
|
||||
MOONRIVER,
|
||||
OKC,
|
||||
ZKSYNC,
|
||||
VICTION,
|
||||
AGORIC,
|
||||
AKASH,
|
||||
AXELAR,
|
||||
BAND_PROTOCOL,
|
||||
BITSONG,
|
||||
CANTO,
|
||||
CHIHUAHUA,
|
||||
COMDEX,
|
||||
COREUM,
|
||||
COSMOS,
|
||||
CRESCENT,
|
||||
CRONOS,
|
||||
CUDOS,
|
||||
DESMOS,
|
||||
DYDX,
|
||||
EVMOS,
|
||||
FETCH_AI,
|
||||
GRAVITY_BRIDGE,
|
||||
INJECTIVE,
|
||||
IRISNET,
|
||||
JUNO,
|
||||
KAVA,
|
||||
KI_NETWORK,
|
||||
MARS_PROTOCOL,
|
||||
NYM,
|
||||
OKEX_CHAIN,
|
||||
ONOMY,
|
||||
OSMOSIS,
|
||||
PERSISTENCE,
|
||||
QUICKSILVER,
|
||||
REGEN,
|
||||
SECRET,
|
||||
SENTINEL,
|
||||
SOMMELIER,
|
||||
STAFI,
|
||||
STARGAZE,
|
||||
STRIDE,
|
||||
TERITORI,
|
||||
TGRADE,
|
||||
UMEE,
|
||||
POLKADOT,
|
||||
KUSAMA,
|
||||
WESTEND,
|
||||
BINANCEBEACON,
|
||||
NEAR,
|
||||
SOLANA,
|
||||
TEZOS,
|
||||
TRON,
|
||||
UNKNOWN,
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package com.tangem.domain.staking.model
|
||||
|
||||
import com.tangem.domain.core.serialization.SerializedBigDecimal
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Yield(
|
||||
val id: String,
|
||||
val token: Token,
|
||||
val tokens: List<Token>,
|
||||
val args: Args,
|
||||
val status: Status,
|
||||
val apy: SerializedBigDecimal,
|
||||
val rewardRate: Double,
|
||||
val rewardType: RewardType,
|
||||
val metadata: Metadata,
|
||||
val validators: List<Validator>,
|
||||
val isAvailable: Boolean,
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Status(
|
||||
val enter: Boolean,
|
||||
val exit: Boolean?,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Args(
|
||||
val enter: Enter,
|
||||
val exit: Enter?,
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Enter(
|
||||
val addresses: Addresses,
|
||||
val args: Map<String, AddressArgument>,
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Addresses(
|
||||
val address: AddressArgument,
|
||||
val additionalAddresses: Map<String, AddressArgument>? = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Validator(
|
||||
val address: String,
|
||||
val status: String,
|
||||
val name: String,
|
||||
val image: String?,
|
||||
val website: String?,
|
||||
val apr: SerializedBigDecimal?,
|
||||
val commission: Double?,
|
||||
val stakedBalance: String?,
|
||||
val votingPower: Double?,
|
||||
val preferred: Boolean,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Metadata(
|
||||
val name: String,
|
||||
val logoUri: String,
|
||||
val description: String,
|
||||
val documentation: String?,
|
||||
val gasFeeToken: Token,
|
||||
val token: Token,
|
||||
val tokens: List<Token>,
|
||||
val type: String,
|
||||
val rewardSchedule: String,
|
||||
val cooldownPeriod: Period,
|
||||
val warmupPeriod: Period,
|
||||
val rewardClaiming: String,
|
||||
val defaultValidator: String?,
|
||||
val minimumStake: Int?,
|
||||
val supportsMultipleValidators: Boolean,
|
||||
val revshare: Enabled,
|
||||
val fee: Enabled,
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Period(
|
||||
val days: Int,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Enabled(
|
||||
val enabled: Boolean,
|
||||
)
|
||||
}
|
||||
|
||||
enum class RewardType {
|
||||
APY, // compound rate
|
||||
APR, // simple rate
|
||||
UNKNOWN,
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Token(
|
||||
val name: String,
|
||||
val network: NetworkType,
|
||||
val symbol: String,
|
||||
val decimals: Int,
|
||||
val address: String?,
|
||||
val coinGeckoId: String?,
|
||||
val logoURI: String?,
|
||||
val isPoints: Boolean?,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class AddressArgument(
|
||||
val required: Boolean,
|
||||
val network: String? = null,
|
||||
val minimum: Double? = null,
|
||||
val maximum: Double? = null,
|
||||
)
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.domain.staking.model.action
|
||||
|
||||
import com.tangem.domain.staking.model.transaction.StakingTransaction
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class EnterAction(
|
||||
val id: String,
|
||||
val integrationId: String,
|
||||
val status: StakingActionStatus,
|
||||
val type: StakingActionType,
|
||||
val currentStepIndex: Int,
|
||||
val amount: BigDecimal,
|
||||
val validatorAddress: String?,
|
||||
val validatorAddresses: List<String>?,
|
||||
val transactions: List<StakingTransaction>?,
|
||||
val createdAt: DateTime,
|
||||
)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.staking.model.action
|
||||
|
||||
enum class StakingActionStatus {
|
||||
CANCELED,
|
||||
CREATED,
|
||||
WAITING_FOR_NEXT,
|
||||
PROCESSING,
|
||||
FAILED,
|
||||
SUCCESS,
|
||||
UNKNOWN,
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.domain.staking.model.action
|
||||
|
||||
enum class StakingActionType {
|
||||
STAKE,
|
||||
UNSTAKE,
|
||||
CLAIM_REWARDS,
|
||||
RESTAKE_REWARDS,
|
||||
WITHDRAW,
|
||||
RESTAKE,
|
||||
CLAIM_UNSTAKED,
|
||||
UNLOCK_LOCKED,
|
||||
STAKE_LOCKED,
|
||||
VOTE,
|
||||
REVOKE,
|
||||
VOTE_LOCKED,
|
||||
REVOTE,
|
||||
REBOND,
|
||||
MIGRATE,
|
||||
UNKNOWN,
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.domain.staking.model.transaction
|
||||
|
||||
import com.tangem.domain.staking.model.Token
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class StakingGasEstimate(
|
||||
val amount: BigDecimal,
|
||||
val token: Token,
|
||||
val gasLimit: BigDecimal,
|
||||
)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.domain.staking.model.transaction
|
||||
|
||||
import com.tangem.domain.staking.model.NetworkType
|
||||
|
||||
data class StakingTransaction(
|
||||
val id: String,
|
||||
val network: NetworkType,
|
||||
val status: StakingTransactionStatus,
|
||||
val type: StakingTransactionType,
|
||||
val hash: String?,
|
||||
val signedTransaction: String?,
|
||||
val unsignedTransaction: String?,
|
||||
val stepIndex: Int,
|
||||
val error: String?,
|
||||
val gasEstimate: StakingGasEstimate?,
|
||||
val stakeId: String?,
|
||||
val explorerUrl: String?,
|
||||
val ledgerHwAppId: String?,
|
||||
val isMessage: Boolean,
|
||||
)
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.domain.staking.model.transaction
|
||||
|
||||
enum class StakingTransactionStatus {
|
||||
NOT_FOUND,
|
||||
CREATED,
|
||||
BLOCKED,
|
||||
WAITING_FOR_SIGNATURE,
|
||||
SIGNED,
|
||||
BROADCASTED,
|
||||
PENDING,
|
||||
CONFIRMED,
|
||||
FAILED,
|
||||
SKIPPED,
|
||||
UNKNOWN,
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.domain.staking.model.transaction
|
||||
|
||||
enum class StakingTransactionType {
|
||||
SWAP,
|
||||
DEPOSIT,
|
||||
APPROVAL,
|
||||
STAKE,
|
||||
CLAIM_UNSTAKED,
|
||||
CLAIM_REWARDS,
|
||||
RESTAKE_REWARDS,
|
||||
UNSTAKE,
|
||||
SPLIT,
|
||||
MERGE,
|
||||
LOCK,
|
||||
UNLOCK,
|
||||
SUPPLY,
|
||||
BRIDGE,
|
||||
VOTE,
|
||||
REVOKE,
|
||||
RESTAKE,
|
||||
REBOND,
|
||||
WITHDRAW,
|
||||
CREATE_ACCOUNT,
|
||||
REVEAL,
|
||||
MIGRATE,
|
||||
UTXO_P_TO_C_IMPORT,
|
||||
UTXO_C_TO_P_IMPORT,
|
||||
UNFREEZE_LEGACY,
|
||||
UNFREEZE_LEGACY_BANDWIDTH,
|
||||
UNFREEZE_LEGACY_ENERGY,
|
||||
UNFREEZE_BANDWIDTH,
|
||||
UNFREEZE_ENERGY,
|
||||
FREEZE_BANDWIDTH,
|
||||
FREEZE_ENERGY,
|
||||
UNDELEGATE_BANDWIDTH,
|
||||
UNDELEGATE_ENERGY,
|
||||
P2P_NODE_REQUEST,
|
||||
LUGANODES_PROVISION,
|
||||
LUGANODES_EXIT_REQUEST,
|
||||
INFSTONES_PROVISION,
|
||||
INFSTONES_EXIT_REQUEST,
|
||||
INFSTONES_CLAIM_REQUEST,
|
||||
UNKNOWN,
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.domain.staking
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.domain.staking.error.StakingTokensError
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
|
||||
/**
|
||||
* Use case for getting enabled tokens
|
||||
*/
|
||||
class FetchStakingTokensUseCase(
|
||||
private val stakingRepository: StakingRepository,
|
||||
) {
|
||||
suspend operator fun invoke(): Either<Throwable, Unit> {
|
||||
return either {
|
||||
catch(
|
||||
block = { stakingRepository.fetchEnabledYields() },
|
||||
catch = { StakingTokensError.DataError(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,16 @@ package com.tangem.domain.staking
|
|||
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
/**
|
||||
* Use case for getting info about staking availability for certain blockchain.
|
||||
* Use case for getting info about staking capability in tangem app.
|
||||
*/
|
||||
class GetStakingAvailabilityUseCase(
|
||||
private val stakingRepository: StakingRepository,
|
||||
) {
|
||||
|
||||
operator fun invoke(blockchainNetworkId: String): StakingAvailability {
|
||||
return stakingRepository.getStakingAvailability(blockchainNetworkId)
|
||||
suspend operator fun invoke(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): StakingAvailability {
|
||||
return stakingRepository.getStakingAvailabilityForActions(cryptoCurrencyId, symbol)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.domain.staking
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.model.Yield
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
/**
|
||||
* Use case for getting staking yield for staking scenario start.
|
||||
*/
|
||||
class GetYieldUseCase(private val stakingRepository: StakingRepository) {
|
||||
|
||||
suspend operator fun invoke(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Either<Throwable, Yield> {
|
||||
return Either.catch { stakingRepository.getYield(cryptoCurrencyId, symbol) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.domain.staking.error
|
||||
|
||||
sealed class StakingTokensError {
|
||||
|
||||
data class DataError(val cause: Throwable) : StakingTokensError()
|
||||
}
|
||||
|
|
@ -5,4 +5,6 @@ sealed class StakingAvailability {
|
|||
data class Available(val integrationId: String) : StakingAvailability()
|
||||
|
||||
data object Unavailable : StakingAvailability()
|
||||
|
||||
data object TemporaryDisabled : StakingAvailability()
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.domain.staking.model
|
||||
|
||||
data class StakingToken(
|
||||
val name: String,
|
||||
val symbol: String,
|
||||
val decimals: Int,
|
||||
val contractAddress: String?,
|
||||
val coinGeckoId: String?,
|
||||
)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.domain.staking.model
|
||||
|
||||
data class StakingTokenWithYield(
|
||||
val token: StakingToken,
|
||||
val availableYieldIds: List<String>,
|
||||
)
|
||||
|
|
@ -2,10 +2,21 @@ package com.tangem.domain.staking.repositories
|
|||
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.staking.model.StakingEntryInfo
|
||||
import com.tangem.domain.staking.model.Yield
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
interface StakingRepository {
|
||||
|
||||
fun getStakingAvailability(blockchainId: String): StakingAvailability
|
||||
fun isStakingSupported(currencyId: String): Boolean
|
||||
|
||||
suspend fun fetchEnabledYields()
|
||||
|
||||
suspend fun getEntryInfo(integrationId: String): StakingEntryInfo
|
||||
|
||||
suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield
|
||||
|
||||
suspend fun getStakingAvailabilityForActions(
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
symbol: String,
|
||||
): StakingAvailability
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ dependencies {
|
|||
api(projects.domain.core)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.staking)
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.txhistory.models)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("kotlin-parcelize")
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(projects.domain.txhistory.models)
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(deps.tangem.blockchain) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.domain.tokens.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a generic cryptocurrency.
|
||||
|
|
@ -14,8 +13,8 @@ import kotlinx.parcelize.Parcelize
|
|||
* @property iconUrl Optional URL of the cryptocurrency icon. `null` if not found.
|
||||
* @property isCustom Indicates whether the currency is a custom user-added currency or not.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class CryptoCurrency : Parcelable {
|
||||
@Serializable
|
||||
sealed class CryptoCurrency {
|
||||
|
||||
abstract val id: ID
|
||||
abstract val network: Network
|
||||
|
|
@ -28,6 +27,7 @@ sealed class CryptoCurrency : Parcelable {
|
|||
/**
|
||||
* Represents a native coin in the blockchain network.
|
||||
*/
|
||||
@Serializable
|
||||
data class Coin(
|
||||
override val id: ID,
|
||||
override val network: Network,
|
||||
|
|
@ -48,6 +48,7 @@ sealed class CryptoCurrency : Parcelable {
|
|||
*
|
||||
* @property contractAddress Address of the contract managing the token.
|
||||
*/
|
||||
@Serializable
|
||||
data class Token(
|
||||
override val id: ID,
|
||||
override val network: Network,
|
||||
|
|
@ -75,12 +76,12 @@ sealed class CryptoCurrency : Parcelable {
|
|||
* @property rawCurrencyId Represents not unique currency ID from the blockchain network. `null` if
|
||||
* its ID of the custom token.
|
||||
*/
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class ID(
|
||||
private val prefix: Prefix,
|
||||
private val body: Body,
|
||||
private val suffix: Suffix,
|
||||
) : Parcelable {
|
||||
) {
|
||||
|
||||
val value: String
|
||||
get() = buildString {
|
||||
|
|
@ -121,12 +122,13 @@ sealed class CryptoCurrency : Parcelable {
|
|||
*
|
||||
* The body can be either a raw network ID or a raw network ID with a network derivation path.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class Body : Parcelable {
|
||||
@Serializable
|
||||
sealed class Body {
|
||||
|
||||
/** The value of the body. */
|
||||
abstract val value: String
|
||||
|
||||
@Serializable
|
||||
/** Represents a raw network ID. */
|
||||
data class NetworkId(val rawId: String) : Body() {
|
||||
override val value: String get() = rawId
|
||||
|
|
@ -137,6 +139,7 @@ sealed class CryptoCurrency : Parcelable {
|
|||
*
|
||||
* Should be used for a cryptocurrencies with custom derivation path.
|
||||
* */
|
||||
@Serializable
|
||||
data class NetworkIdWithDerivationPath(
|
||||
val rawId: String,
|
||||
val derivationPath: String,
|
||||
|
|
@ -155,13 +158,14 @@ sealed class CryptoCurrency : Parcelable {
|
|||
*
|
||||
* The suffix can either be a raw ID or a contract address.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class Suffix : Parcelable {
|
||||
@Serializable
|
||||
sealed class Suffix {
|
||||
|
||||
/** The value of the suffix, which could be either a raw ID or a contract address. */
|
||||
abstract val value: String
|
||||
|
||||
/** Represents a raw ID suffix. */
|
||||
@Serializable
|
||||
data class RawID(val rawId: String, val contractAddress: String? = null) : Suffix() {
|
||||
override val value: String
|
||||
get() = buildString {
|
||||
|
|
@ -174,6 +178,7 @@ sealed class CryptoCurrency : Parcelable {
|
|||
}
|
||||
|
||||
/** Represents a contract address suffix. */
|
||||
@Serializable
|
||||
data class ContractAddress(val contractAddress: String) : Suffix() {
|
||||
override val value: String get() = contractAddress
|
||||
}
|
||||
|
|
@ -183,11 +188,11 @@ sealed class CryptoCurrency : Parcelable {
|
|||
return "ID(value='$value')"
|
||||
}
|
||||
|
||||
private companion object {
|
||||
companion object {
|
||||
// should use delimiters that could be used in URL not like path or query delimiters
|
||||
const val PREFIX_DELIMITER = '_'
|
||||
const val SUFFIX_DELIMITER = ';'
|
||||
const val DERIVATION_PATH_DELIMITER = 'd'
|
||||
private const val PREFIX_DELIMITER = '_'
|
||||
private const val SUFFIX_DELIMITER = ';'
|
||||
private const val DERIVATION_PATH_DELIMITER = 'd'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.domain.tokens.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a blockchain network, identified by a unique ID, a human-readable name, and its standard type.
|
||||
|
|
@ -20,7 +19,7 @@ import kotlinx.parcelize.Parcelize
|
|||
* that cannot be represented in a fiat currency.
|
||||
* (For those blockchains that have FeeResource instead of a standard type of fee)
|
||||
*/
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class Network(
|
||||
val id: ID,
|
||||
val backendId: String,
|
||||
|
|
@ -30,7 +29,7 @@ data class Network(
|
|||
val isTestnet: Boolean,
|
||||
val standardType: StandardType,
|
||||
val hasFiatFeeRate: Boolean,
|
||||
) : Parcelable {
|
||||
) {
|
||||
|
||||
init {
|
||||
require(name.isNotBlank()) { "Network name must not be blank" }
|
||||
|
|
@ -42,8 +41,8 @@ data class Network(
|
|||
* @property value The string representation of the network ID.
|
||||
*/
|
||||
@JvmInline
|
||||
@Parcelize
|
||||
value class ID(val value: String) : Parcelable {
|
||||
@Serializable
|
||||
value class ID(val value: String) {
|
||||
|
||||
init {
|
||||
require(value.isNotBlank()) { "Network ID must not be blank" }
|
||||
|
|
@ -56,8 +55,8 @@ data class Network(
|
|||
* This class represents such paths in a generic manner, allowing for predefined card-based paths,
|
||||
* custom paths, or even no derivation path at all.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class DerivationPath : Parcelable {
|
||||
@Serializable
|
||||
sealed class DerivationPath {
|
||||
|
||||
/** The actual derivation path value, if any. */
|
||||
abstract val value: String?
|
||||
|
|
@ -67,6 +66,7 @@ data class Network(
|
|||
*
|
||||
* @property value The derivation path string.
|
||||
*/
|
||||
@Serializable
|
||||
data class Card(override val value: String) : DerivationPath()
|
||||
|
||||
/**
|
||||
|
|
@ -74,12 +74,14 @@ data class Network(
|
|||
*
|
||||
* @property value The derivation path string.
|
||||
*/
|
||||
@Serializable
|
||||
data class Custom(override val value: String) : DerivationPath()
|
||||
|
||||
/**
|
||||
* Represents a lack of derivation path.
|
||||
*/
|
||||
object None : DerivationPath() {
|
||||
@Serializable
|
||||
data object None : DerivationPath() {
|
||||
override val value: String? get() = null
|
||||
}
|
||||
}
|
||||
|
|
@ -93,31 +95,36 @@ data class Network(
|
|||
*
|
||||
* @property name The human-readable name of the standard type.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class StandardType : Parcelable {
|
||||
@Serializable
|
||||
sealed class StandardType {
|
||||
abstract val name: String
|
||||
|
||||
/** Represents the ERC20 token standard, common on the Ethereum network. */
|
||||
object ERC20 : StandardType() {
|
||||
@Serializable
|
||||
data object ERC20 : StandardType() {
|
||||
override val name: String get() = "ERC20"
|
||||
}
|
||||
|
||||
/** Represents the TRC20 token standard, common on the TRON network. */
|
||||
object TRC20 : StandardType() {
|
||||
@Serializable
|
||||
data object TRC20 : StandardType() {
|
||||
override val name: String get() = "TRC20"
|
||||
}
|
||||
|
||||
/** Represents the BEP20 token standard, common on the Binance Smart Chain network. */
|
||||
object BEP20 : StandardType() {
|
||||
@Serializable
|
||||
data object BEP20 : StandardType() {
|
||||
override val name: String get() = "BEP20"
|
||||
}
|
||||
|
||||
/** Represents the BEP2 token standard, common on the Binance Chain network. */
|
||||
object BEP2 : StandardType() {
|
||||
@Serializable
|
||||
data object BEP2 : StandardType() {
|
||||
override val name: String get() = "BEP2"
|
||||
}
|
||||
|
||||
/** Represents a network that does not adhere to a predefined standard type. */
|
||||
@Serializable
|
||||
data class Unspecified(override val name: String) : StandardType()
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ package com.tangem.domain.tokens
|
|||
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
|
|
@ -28,6 +30,7 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
|
|
@ -121,6 +124,17 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
activeList.add(TokenActionsState.ActionState.Receive(scenario))
|
||||
}
|
||||
|
||||
// staking
|
||||
if (isStakingAvailable(cryptoCurrency)) {
|
||||
activeList.add(TokenActionsState.ActionState.Stake(ScenarioUnavailabilityReason.None))
|
||||
} else {
|
||||
disabledList.add(
|
||||
TokenActionsState.ActionState.Stake(
|
||||
unavailabilityReason = ScenarioUnavailabilityReason.StakingUnavailable(cryptoCurrency.name),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// send
|
||||
val sendUnavailabilityReason = getSendUnavailabilityReason(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
|
|
@ -234,6 +248,7 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
}
|
||||
actionsList.add(TokenActionsState.ActionState.Receive(scenario))
|
||||
}
|
||||
actionsList.add(TokenActionsState.ActionState.Stake(ScenarioUnavailabilityReason.Unreachable))
|
||||
actionsList.add(TokenActionsState.ActionState.HideToken(ScenarioUnavailabilityReason.None))
|
||||
return actionsList
|
||||
}
|
||||
|
|
@ -246,7 +261,7 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
cryptoCurrencyStatus.value.amount.isNullOrZero() -> {
|
||||
ScenarioUnavailabilityReason.EmptyBalance(ScenarioUnavailabilityReason.WithdrawalScenario.SEND)
|
||||
}
|
||||
currenciesRepository.hasPendingTransactions(
|
||||
currenciesRepository.isSendBlockedByPendingTransactions(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
coinStatus = coinStatus,
|
||||
) -> {
|
||||
|
|
@ -264,4 +279,11 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
private fun isAddressAvailable(networkAddress: NetworkAddress?): Boolean {
|
||||
return networkAddress != null && networkAddress.defaultAddress.value.isNotEmpty()
|
||||
}
|
||||
|
||||
private suspend fun isStakingAvailable(cryptoCurrency: CryptoCurrency): Boolean {
|
||||
return stakingRepository.getStakingAvailabilityForActions(
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
symbol = cryptoCurrency.symbol,
|
||||
) is StakingAvailability.Available
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,9 @@ package com.tangem.domain.tokens.model
|
|||
sealed class ScenarioUnavailabilityReason {
|
||||
data object None : ScenarioUnavailabilityReason()
|
||||
|
||||
// staking-specific
|
||||
data class StakingUnavailable(val cryptoCurrencyName: String) : ScenarioUnavailabilityReason()
|
||||
|
||||
// send&sell-specific
|
||||
data class PendingTransaction(
|
||||
val withdrawalScenario: WithdrawalScenario,
|
||||
|
|
@ -24,6 +27,6 @@ sealed class ScenarioUnavailabilityReason {
|
|||
data object UnassociatedAsset : ScenarioUnavailabilityReason()
|
||||
|
||||
enum class WithdrawalScenario {
|
||||
SELL, SEND
|
||||
SELL, SEND // TODO staking create&process STAKING
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@ data class TokenActionsState(
|
|||
|
||||
data class Receive(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
||||
|
||||
data class Stake(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
||||
|
||||
data class Swap(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
||||
|
||||
data class Send(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
||||
|
|
|
|||
|
|
@ -194,12 +194,15 @@ interface CurrenciesRepository {
|
|||
fun getMissedAddressesCryptoCurrencies(userWalletId: UserWalletId): Flow<List<CryptoCurrency>>
|
||||
|
||||
/**
|
||||
* Determines whether the currency has pending transaction or currency network has pending transaction
|
||||
* Determines whether the currency sending is blocked by network pending transaction
|
||||
*
|
||||
* @param cryptoCurrencyStatus currency status
|
||||
* @param coinStatus main currency status in [cryptoCurrencyStatus] network
|
||||
*/
|
||||
fun hasPendingTransactions(cryptoCurrencyStatus: CryptoCurrencyStatus, coinStatus: CryptoCurrencyStatus?): Boolean
|
||||
fun isSendBlockedByPendingTransactions(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
coinStatus: CryptoCurrencyStatus?,
|
||||
): Boolean
|
||||
|
||||
/**
|
||||
* Retrieves fee paid currency for specific [currency].
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ internal class MockCurrenciesRepository(
|
|||
return isSortedByBalance.map { it.getOrElse { e -> throw e } }
|
||||
}
|
||||
|
||||
override fun hasPendingTransactions(
|
||||
override fun isSendBlockedByPendingTransactions(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
coinStatus: CryptoCurrencyStatus?,
|
||||
): Boolean {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -11,4 +12,8 @@ dependencies {
|
|||
// region Domain modules
|
||||
implementation(project(":domain:models"))
|
||||
// endregion
|
||||
|
||||
// region Other libraries
|
||||
implementation(deps.kotlin.serialization)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -2,9 +2,10 @@ package com.tangem.domain.wallets.models
|
|||
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import java.io.Serializable
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
data class UserWalletId(val stringValue: String) : Serializable {
|
||||
@Serializable
|
||||
data class UserWalletId(val stringValue: String) {
|
||||
|
||||
val value = stringValue.hexToBytes()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue