Updated on 2026-08-14
This commit is contained in:
parent
8c8e00e7b4
commit
95b6933a14
15 changed files with 205 additions and 9 deletions
|
|
@ -1,13 +1,9 @@
|
||||||
package com.tangem.tap.domain.tokens
|
package com.tangem.tap.domain.tokens
|
||||||
|
|
||||||
import com.tangem.core.configtoggle.FeatureToggles
|
|
||||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||||
|
|
||||||
|
@Suppress("UnusedPrivateProperty")
|
||||||
internal class DefaultTokensFeatureToggles(
|
internal class DefaultTokensFeatureToggles(
|
||||||
private val featureTogglesManager: FeatureTogglesManager,
|
private val featureTogglesManager: FeatureTogglesManager,
|
||||||
) : TokensFeatureToggles {
|
) : TokensFeatureToggles
|
||||||
|
|
||||||
override val isDynamicAddressesEnabled: Boolean
|
|
||||||
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.DYNAMIC_ADDRESSES_ENABLED)
|
|
||||||
}
|
|
||||||
20
domain/dynamic-addresses/build.gradle.kts
Normal file
20
domain/dynamic-addresses/build.gradle.kts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
plugins {
|
||||||
|
alias(deps.plugins.android.library)
|
||||||
|
alias(deps.plugins.kotlin.android)
|
||||||
|
id("configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.tangem.domain.dynamicaddresses"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(projects.domain.core)
|
||||||
|
api(projects.domain.dynamicAddresses.models)
|
||||||
|
|
||||||
|
implementation(projects.domain.models)
|
||||||
|
|
||||||
|
implementation(tangemDeps.blockchain) {
|
||||||
|
exclude(module = "joda-time")
|
||||||
|
}
|
||||||
|
}
|
||||||
7
domain/dynamic-addresses/models/build.gradle.kts
Normal file
7
domain/dynamic-addresses/models/build.gradle.kts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
plugins {
|
||||||
|
alias(deps.plugins.kotlin.jvm)
|
||||||
|
id("configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses.model
|
||||||
|
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
data class ConsolidationInfo(
|
||||||
|
val fee: BigDecimal,
|
||||||
|
val inputCount: Int,
|
||||||
|
val canCoverFee: Boolean,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses.model
|
||||||
|
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
enum class DynamicAddressesStatus {
|
||||||
|
ENABLED,
|
||||||
|
|
||||||
|
DISABLED,
|
||||||
|
|
||||||
|
/** Enabled on backend, but local XPUB setup required (cross-device sync) */
|
||||||
|
ENABLED_REQUIRES_SETUP,
|
||||||
|
}
|
||||||
|
|
||||||
|
data class UsedAddress(
|
||||||
|
val address: String,
|
||||||
|
val path: String,
|
||||||
|
val balance: BigDecimal,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses
|
||||||
|
|
||||||
|
import arrow.core.Either
|
||||||
|
import arrow.core.getOrElse
|
||||||
|
import arrow.core.raise.either
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.dynamicaddresses.model.ConsolidationInfo
|
||||||
|
import com.tangem.domain.dynamicaddresses.repository.ConsolidationRepository
|
||||||
|
import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository
|
||||||
|
|
||||||
|
class DisableDynamicAddressesUseCase(
|
||||||
|
private val dynamicAddressesRepository: DynamicAddressesRepository,
|
||||||
|
private val consolidationRepository: ConsolidationRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [ConsolidationInfo] when consolidation is required before disabling,
|
||||||
|
* or null when DA can be disabled immediately (no non-base balances).
|
||||||
|
*/
|
||||||
|
suspend operator fun invoke(userWalletId: UserWalletId, network: Network): Either<Throwable, ConsolidationInfo?> =
|
||||||
|
either {
|
||||||
|
val hasNonBaseBalances = dynamicAddressesRepository.hasNonBaseBalances(userWalletId, network)
|
||||||
|
|
||||||
|
if (!hasNonBaseBalances) {
|
||||||
|
dynamicAddressesRepository.disable(userWalletId, network)
|
||||||
|
return@either null
|
||||||
|
}
|
||||||
|
|
||||||
|
consolidationRepository.getConsolidationInfo(userWalletId, network)
|
||||||
|
.getOrElse { raise(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses
|
||||||
|
|
||||||
|
interface DynamicAddressesFeatureToggles {
|
||||||
|
|
||||||
|
val isDynamicAddressesEnabled: Boolean
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses
|
||||||
|
|
||||||
|
import arrow.core.Either
|
||||||
|
import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
|
class EnableDynamicAddressesUseCase(
|
||||||
|
private val dynamicAddressesRepository: DynamicAddressesRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(userWalletId: UserWalletId, network: Network, xpub: String): Either<Throwable, Unit> =
|
||||||
|
Either.catch {
|
||||||
|
dynamicAddressesRepository.enable(userWalletId, network, xpub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses
|
||||||
|
|
||||||
|
import arrow.core.Either
|
||||||
|
import com.tangem.domain.dynamicaddresses.model.ConsolidationInfo
|
||||||
|
import com.tangem.domain.dynamicaddresses.repository.ConsolidationRepository
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
|
class GetConsolidationInfoUseCase(
|
||||||
|
private val consolidationRepository: ConsolidationRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(userWalletId: UserWalletId, network: Network): Either<Throwable, ConsolidationInfo> {
|
||||||
|
return consolidationRepository.getConsolidationInfo(userWalletId, network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses
|
||||||
|
|
||||||
|
import com.tangem.domain.dynamicaddresses.model.DynamicAddressesStatus
|
||||||
|
import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
class GetDynamicAddressesStatusUseCase(
|
||||||
|
private val dynamicAddressesRepository: DynamicAddressesRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
operator fun invoke(userWalletId: UserWalletId, network: Network): Flow<DynamicAddressesStatus> {
|
||||||
|
return dynamicAddressesRepository.getStatus(userWalletId, network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses
|
||||||
|
|
||||||
|
import arrow.core.Either
|
||||||
|
import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
|
class GetDynamicReceiveAddressUseCase(
|
||||||
|
private val dynamicAddressesRepository: DynamicAddressesRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(userWalletId: UserWalletId, network: Network): Either<Throwable, String> =
|
||||||
|
Either.catch {
|
||||||
|
dynamicAddressesRepository.getReceiveAddress(userWalletId, network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses.repository
|
||||||
|
|
||||||
|
import arrow.core.Either
|
||||||
|
import com.tangem.blockchain.common.TransactionSigner
|
||||||
|
import com.tangem.domain.dynamicaddresses.model.ConsolidationInfo
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
|
interface ConsolidationRepository {
|
||||||
|
|
||||||
|
suspend fun getConsolidationInfo(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
network: Network,
|
||||||
|
): Either<Throwable, ConsolidationInfo>
|
||||||
|
|
||||||
|
suspend fun sendConsolidationTransaction(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
network: Network,
|
||||||
|
signer: TransactionSigner,
|
||||||
|
): Either<Throwable, String>
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.tangem.domain.dynamicaddresses.repository
|
||||||
|
|
||||||
|
import com.tangem.domain.dynamicaddresses.model.DynamicAddressesStatus
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface DynamicAddressesRepository {
|
||||||
|
|
||||||
|
fun getStatus(userWalletId: UserWalletId, network: Network): Flow<DynamicAddressesStatus>
|
||||||
|
|
||||||
|
suspend fun enable(userWalletId: UserWalletId, network: Network, xpub: String)
|
||||||
|
|
||||||
|
suspend fun disable(userWalletId: UserWalletId, network: Network)
|
||||||
|
|
||||||
|
suspend fun getReceiveAddress(userWalletId: UserWalletId, network: Network): String
|
||||||
|
|
||||||
|
// for explorer url
|
||||||
|
suspend fun getLastUsedReceiveAddress(userWalletId: UserWalletId, network: Network): String?
|
||||||
|
|
||||||
|
suspend fun hasNonBaseBalances(userWalletId: UserWalletId, network: Network): Boolean
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,4 @@ package com.tangem.domain.tokens
|
||||||
*
|
*
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
interface TokensFeatureToggles {
|
interface TokensFeatureToggles
|
||||||
val isDynamicAddressesEnabled: Boolean
|
|
||||||
}
|
|
||||||
|
|
@ -335,6 +335,8 @@ include(":domain:common")
|
||||||
include(":domain:core")
|
include(":domain:core")
|
||||||
include(":domain:demo")
|
include(":domain:demo")
|
||||||
include(":domain:demo:models")
|
include(":domain:demo:models")
|
||||||
|
include(":domain:dynamic-addresses")
|
||||||
|
include(":domain:dynamic-addresses:models")
|
||||||
include(":domain:settings")
|
include(":domain:settings")
|
||||||
include(":domain:tokens")
|
include(":domain:tokens")
|
||||||
include(":domain:tokens:models")
|
include(":domain:tokens:models")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue