Updated on 2026-08-14
This commit is contained in:
parent
538757a7ce
commit
a2b440444e
12 changed files with 300 additions and 101 deletions
|
|
@ -9,7 +9,7 @@ import com.tangem.common.extensions.hexToBytes
|
|||
import com.tangem.common.extensions.toDecompressedPublicKey
|
||||
import com.tangem.data.walletconnect.respond.WcRespondService
|
||||
import com.tangem.data.walletconnect.sign.BaseWcSignUseCase
|
||||
import com.tangem.data.walletconnect.sign.OnSign
|
||||
import com.tangem.data.walletconnect.sign.SignCollector
|
||||
import com.tangem.data.walletconnect.sign.SignStateConverter.toResult
|
||||
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
|
||||
import com.tangem.domain.transaction.usecase.SignUseCase
|
||||
|
|
@ -33,15 +33,17 @@ internal class DefaultWcEthMessageSignUseCase @AssistedInject constructor(
|
|||
) : BaseWcSignUseCase<Nothing, WcEthMessageSignUseCase.SignModel>(),
|
||||
WcEthMessageSignUseCase {
|
||||
|
||||
override val onSign: OnSign<WcEthMessageSignUseCase.SignModel> = collector@{ state ->
|
||||
override suspend fun SignCollector<WcEthMessageSignUseCase.SignModel>.onSign(
|
||||
state: WcSignState<WcEthMessageSignUseCase.SignModel>,
|
||||
) {
|
||||
val hashToSign = LegacySdkHelper.createMessageData(state.signModel.rawMsg)
|
||||
val userWallet = session.wallet
|
||||
val walletManager = walletManagersFacade.getOrCreateWalletManager(userWallet.walletId, network)
|
||||
?: return@collector
|
||||
?: return
|
||||
|
||||
val signedHash = signUseCase(hashToSign, userWallet, network)
|
||||
.onLeft { emit(state.toResult(it.left())) }
|
||||
.getOrNull() ?: return@collector
|
||||
.getOrNull() ?: return
|
||||
|
||||
val respond = EthereumUtils.prepareSignedMessageData(
|
||||
signedHash = signedHash,
|
||||
|
|
|
|||
|
|
@ -1,50 +1,53 @@
|
|||
package com.tangem.data.walletconnect.network.ethereum
|
||||
|
||||
import arrow.core.left
|
||||
import com.tangem.blockchain.common.HEX_PREFIX
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.extensions.formatHex
|
||||
import com.tangem.data.walletconnect.respond.WcRespondService
|
||||
import com.tangem.data.walletconnect.sign.BaseWcSignUseCase
|
||||
import com.tangem.data.walletconnect.sign.OnSign
|
||||
import com.tangem.data.walletconnect.sign.SignCollector
|
||||
import com.tangem.data.walletconnect.sign.SignStateConverter.toResult
|
||||
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.walletconnect.model.WcEthMethod
|
||||
import com.tangem.domain.walletconnect.usecase.ethereum.WcEthSendTransactionUseCase
|
||||
import com.tangem.domain.walletconnect.usecase.ethereum.WcEthTransaction
|
||||
import com.tangem.domain.walletconnect.usecase.sign.WcSignState
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
internal class DefaultWcEthSendTransactionUseCase @AssistedInject constructor(
|
||||
@Assisted override val context: WcMethodUseCaseContext,
|
||||
@Assisted private val method: WcEthMethod.SendTransaction,
|
||||
override val respondService: WcRespondService,
|
||||
private val sendTransaction: SendTransactionUseCase,
|
||||
) : BaseWcSignUseCase<Nothing, TransactionData>(),
|
||||
) : BaseWcSignUseCase<Fee, WcEthTransaction>(),
|
||||
WcEthSendTransactionUseCase {
|
||||
|
||||
override val onSign: OnSign<TransactionData> = collector@{ state ->
|
||||
val hash = sendTransaction(state.signModel, wallet, network)
|
||||
private val converter = EthTransactionParamsConverter(context)
|
||||
|
||||
override suspend fun SignCollector<WcEthTransaction>.onSign(state: WcSignState<WcEthTransaction>) {
|
||||
val hash = sendTransaction(state.signModel.transactionData, wallet, network)
|
||||
.onLeft { error ->
|
||||
val sendError = IllegalArgumentException(error.toString()) // todo(wc) use domain error
|
||||
emit(state.toResult(sendError.left()))
|
||||
}
|
||||
.getOrNull() ?: return@collector
|
||||
val respondHash = if (hash.startsWith(HEX_PREFIX)) hash else HEX_PREFIX + hash
|
||||
val respondResult = respondService.respond(rawSdkRequest, respondHash)
|
||||
.getOrNull() ?: return
|
||||
val respondResult = respondService.respond(rawSdkRequest, hash.formatHex())
|
||||
emit(state.toResult(respondResult))
|
||||
}
|
||||
|
||||
override fun updateFee(fee: TransactionFee) {
|
||||
TODO("Not yet implemented")
|
||||
override fun updateFee(fee: Fee) {
|
||||
middleAction(fee)
|
||||
}
|
||||
|
||||
override fun invoke(): Flow<WcSignState<TransactionData>> {
|
||||
method
|
||||
TODO("Not yet implemented")
|
||||
override fun invoke(): Flow<WcSignState<WcEthTransaction>> = flow {
|
||||
val ethTransaction = converter.convert(method.transaction) ?: return@flow
|
||||
emitAll(delegate.invoke(ethTransaction))
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -1,51 +1,62 @@
|
|||
package com.tangem.data.walletconnect.network.ethereum
|
||||
|
||||
import arrow.core.left
|
||||
import com.tangem.blockchain.common.HEX_PREFIX
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.extensions.formatHex
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.data.walletconnect.respond.WcRespondService
|
||||
import com.tangem.data.walletconnect.sign.BaseWcSignUseCase
|
||||
import com.tangem.data.walletconnect.sign.OnSign
|
||||
import com.tangem.data.walletconnect.sign.SignCollector
|
||||
import com.tangem.data.walletconnect.sign.SignStateConverter.toResult
|
||||
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
|
||||
import com.tangem.domain.transaction.usecase.PrepareForSendUseCase
|
||||
import com.tangem.domain.walletconnect.model.WcEthMethod
|
||||
import com.tangem.domain.walletconnect.usecase.ethereum.WcEthSignTransactionUseCase
|
||||
import com.tangem.domain.walletconnect.usecase.ethereum.WcEthTransaction
|
||||
import com.tangem.domain.walletconnect.usecase.sign.WcSignState
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
internal class DefaultWcEthSignTransactionUseCase @AssistedInject constructor(
|
||||
override val respondService: WcRespondService,
|
||||
private val prepareForSend: PrepareForSendUseCase,
|
||||
@Assisted override val context: WcMethodUseCaseContext,
|
||||
@Assisted private val method: WcEthMethod.SignTransaction,
|
||||
) : BaseWcSignUseCase<Nothing, TransactionData>(),
|
||||
) : BaseWcSignUseCase<Fee, WcEthTransaction>(),
|
||||
WcEthSignTransactionUseCase {
|
||||
|
||||
override val onSign: OnSign<TransactionData> = collector@{ state ->
|
||||
val hash = prepareForSend(state.signModel, wallet, network)
|
||||
private val converter = EthTransactionParamsConverter(context)
|
||||
|
||||
override suspend fun SignCollector<WcEthTransaction>.onSign(state: WcSignState<WcEthTransaction>) {
|
||||
val hash = prepareForSend(state.signModel.transactionData, wallet, network)
|
||||
.map { it.toHexString().formatHex() }
|
||||
.onLeft { error ->
|
||||
emit(state.toResult(error.left()))
|
||||
}
|
||||
.getOrNull() ?: return@collector
|
||||
val hashString = hash.toHexString()
|
||||
val respondHash = if (hashString.startsWith(HEX_PREFIX)) hashString else HEX_PREFIX + hashString
|
||||
val respondResult = respondService.respond(rawSdkRequest, respondHash)
|
||||
.getOrNull()
|
||||
?: return
|
||||
val respondResult = respondService.respond(rawSdkRequest, hash)
|
||||
emit(state.toResult(respondResult))
|
||||
}
|
||||
|
||||
override fun updateFee(fee: TransactionFee) {
|
||||
TODO("Not yet implemented")
|
||||
override suspend fun FlowCollector<WcEthTransaction>.onMiddleAction(signModel: WcEthTransaction, fee: Fee) {
|
||||
val newState = signModel
|
||||
.copy(transactionData = signModel.transactionData.copy(fee = fee))
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun invoke(): Flow<WcSignState<TransactionData>> {
|
||||
method
|
||||
TODO("Not yet implemented")
|
||||
override fun updateFee(fee: Fee) {
|
||||
middleAction(fee)
|
||||
}
|
||||
|
||||
override fun invoke(): Flow<WcSignState<WcEthTransaction>> = flow {
|
||||
val ethTransaction = converter.convert(method.transaction) ?: return@flow
|
||||
emitAll(delegate.invoke(ethTransaction))
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.data.walletconnect.network.ethereum
|
||||
|
||||
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
|
||||
import com.tangem.domain.walletconnect.model.WcEthTransactionParams
|
||||
import com.tangem.domain.walletconnect.usecase.ethereum.WcEthTransaction
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class EthTransactionParamsConverter(
|
||||
private val context: WcMethodUseCaseContext,
|
||||
) : Converter<WcEthTransactionParams, WcEthTransaction?> {
|
||||
|
||||
override fun convert(value: WcEthTransactionParams): WcEthTransaction? {
|
||||
val dAppFee = WcEthTxHelper.getDAppFee(context.network, value)
|
||||
val transactionData = WcEthTxHelper.createTransactionData(
|
||||
dAppFee = dAppFee,
|
||||
network = context.network,
|
||||
txParams = value,
|
||||
)
|
||||
transactionData ?: return null
|
||||
return WcEthTransaction(
|
||||
dAppFee = dAppFee,
|
||||
transactionData = transactionData,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.tangem.data.walletconnect.network.ethereum
|
||||
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.HEX_PREFIX
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.smartcontract.CompiledSmartContractCallData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.extensions.hexToBigDecimal
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.walletconnect.model.WcEthTransactionParams
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal object WcEthTxHelper {
|
||||
private val MANTLE_FEE_ESTIMATE_MULTIPLIER = BigDecimal("1.8")
|
||||
|
||||
fun getDAppFee(network: Network, txParams: WcEthTransactionParams): Fee.Ethereum.Legacy? {
|
||||
val gasLimit = txParams.gas?.hexToBigDecimal() ?: return null
|
||||
val gasPrice = txParams.gasPrice?.hexToBigDecimal() ?: return null
|
||||
|
||||
val blockchain = Blockchain.fromId(network.id.value)
|
||||
|
||||
var feeDecimal = (gasLimit * gasPrice)
|
||||
.movePointLeft(blockchain.decimals())
|
||||
if (blockchain == Blockchain.Mantle) {
|
||||
feeDecimal = feeDecimal.multiply(MANTLE_FEE_ESTIMATE_MULTIPLIER)
|
||||
}
|
||||
|
||||
val feeAmount = Amount(feeDecimal, blockchain)
|
||||
return Fee.Ethereum.Legacy(feeAmount, gasLimit.toBigInteger(), gasPrice.toBigInteger())
|
||||
}
|
||||
|
||||
fun createTransactionData(
|
||||
dAppFee: Fee.Ethereum.Legacy?,
|
||||
network: Network,
|
||||
txParams: WcEthTransactionParams,
|
||||
): TransactionData.Uncompiled? {
|
||||
val destinationAddress = txParams.to ?: return null
|
||||
val blockchain = Blockchain.fromId(network.id.value)
|
||||
val value = (txParams.value ?: "0")
|
||||
.hexToBigDecimal()
|
||||
.movePointLeft(blockchain.decimals())
|
||||
|
||||
val callData = CompiledSmartContractCallData(txParams.data.removePrefix(HEX_PREFIX).hexToBytes())
|
||||
return TransactionData.Uncompiled(
|
||||
amount = Amount(value, blockchain),
|
||||
fee = dAppFee,
|
||||
sourceAddress = txParams.from,
|
||||
destinationAddress = destinationAddress,
|
||||
extras = EthereumTransactionExtras(
|
||||
callData = callData,
|
||||
nonce = txParams.nonce?.hexToBigDecimal()?.toBigInteger(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ internal abstract class BaseWcSignUseCase<MiddleAction, SignModel> :
|
|||
)
|
||||
}
|
||||
|
||||
override val onCancel: suspend (currentState: WcSignState<SignModel>) -> Unit = {
|
||||
override suspend fun onCancel(currentState: WcSignState<SignModel>) {
|
||||
defaultReject()
|
||||
}
|
||||
|
||||
|
|
@ -46,14 +46,14 @@ internal abstract class BaseWcSignUseCase<MiddleAction, SignModel> :
|
|||
|
||||
internal interface MiddleActionCollector<MiddleAction, SignModel> {
|
||||
|
||||
val onMiddleAction: OnMiddle<MiddleAction, SignModel> get() = { _, _ -> }
|
||||
suspend fun FlowCollector<SignModel>.onMiddleAction(signModel: SignModel, middleAction: MiddleAction) {}
|
||||
}
|
||||
|
||||
internal interface FinalActionCollector<SignModel> {
|
||||
|
||||
val onSign: OnSign<SignModel> get() = {}
|
||||
suspend fun SignCollector<SignModel>.onSign(state: WcSignState<SignModel>) {}
|
||||
|
||||
val onCancel: OnCancel<SignModel> get() = {}
|
||||
suspend fun onCancel(state: WcSignState<SignModel>) {}
|
||||
}
|
||||
|
||||
internal class WcMethodUseCaseContext(
|
||||
|
|
@ -62,9 +62,4 @@ internal class WcMethodUseCaseContext(
|
|||
val network: Network,
|
||||
)
|
||||
|
||||
internal typealias OnSign<SignModel> =
|
||||
suspend FlowCollector<WcSignState<SignModel>>.(state: WcSignState<SignModel>) -> Unit
|
||||
internal typealias OnCancel<SignModel> =
|
||||
suspend (currentState: WcSignState<SignModel>) -> Unit
|
||||
internal typealias OnMiddle<MiddleAction, SignModel> =
|
||||
suspend FlowCollector<SignModel>.(currentState: WcSignState<SignModel>, middleAction: MiddleAction) -> Unit
|
||||
internal typealias SignCollector<SignModel> = FlowCollector<WcSignState<SignModel>>
|
||||
|
|
@ -42,7 +42,7 @@ internal class WcSignUseCaseDelegate<MiddleAction, SignModel>(
|
|||
|
||||
fun listenMiddle() = middleActionsChannel.receiveAsFlow()
|
||||
.buffer()
|
||||
.transform { middleActions -> this.onMiddleAction(state.value, middleActions) }
|
||||
.transform { middleActions -> this.onMiddleAction(state.value.signModel, middleActions) }
|
||||
.onEach { updatedModel -> state.update { it.toPreSign(updatedModel) } }
|
||||
.launchIn(this)
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ internal class WcSignUseCaseDelegate<MiddleAction, SignModel>(
|
|||
.transformLatest<Action, Unit> { finalAction ->
|
||||
when (finalAction) {
|
||||
Action.Cancel -> {
|
||||
onCancel.invoke(state.value)
|
||||
onCancel(state.value)
|
||||
channel.close()
|
||||
}
|
||||
Action.Sign -> {
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@ import arrow.core.left
|
|||
import arrow.core.right
|
||||
import com.tangem.data.walletconnect.sign.FinalActionCollector
|
||||
import com.tangem.data.walletconnect.sign.MiddleActionCollector
|
||||
import com.tangem.data.walletconnect.sign.SignCollector
|
||||
import com.tangem.data.walletconnect.sign.SignStateConverter.toResult
|
||||
import com.tangem.data.walletconnect.sign.SignStateConverter.toSigning
|
||||
import com.tangem.data.walletconnect.sign.WcSignUseCaseDelegate
|
||||
import com.tangem.domain.walletconnect.usecase.sign.WcSignState
|
||||
import com.tangem.domain.walletconnect.usecase.sign.WcSignStep
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
|
|
@ -21,12 +20,10 @@ import org.junit.Test
|
|||
|
||||
internal class WcSignUseCaseDelegateTest {
|
||||
|
||||
private val middleActionCollector = mockk<MiddleActionCollector<TestMiddleAction, TestSignModel>>()
|
||||
private val finalActionCollector = mockk<FinalActionCollector<TestSignModel>>()
|
||||
private val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
private var middleActionCollector: MiddleActionCollector<TestMiddleAction, TestSignModel> =
|
||||
object : MiddleActionCollector<TestMiddleAction, TestSignModel> {}
|
||||
private var finalActionCollector: FinalActionCollector<TestSignModel> =
|
||||
object : FinalActionCollector<TestSignModel> {}
|
||||
private val initSignModel = TestSignModel()
|
||||
|
||||
private val initState = WcSignState(initSignModel, WcSignStep.PreSign)
|
||||
|
|
@ -51,14 +48,21 @@ internal class WcSignUseCaseDelegateTest {
|
|||
|
||||
@Before
|
||||
fun setup() {
|
||||
every { middleActionCollector.onMiddleAction } returns { _, _ -> }
|
||||
every { finalActionCollector.onSign } returns { }
|
||||
every { finalActionCollector.onCancel } returns { }
|
||||
middleActionCollector = object : MiddleActionCollector<TestMiddleAction, TestSignModel> {}
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `invoke and keep flow running`() = runTest {
|
||||
every { finalActionCollector.onSign } returns successSign
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {
|
||||
override suspend fun SignCollector<TestSignModel>.onSign(state: WcSignState<TestSignModel>) {
|
||||
successSign(state)
|
||||
}
|
||||
}
|
||||
val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
|
||||
useCase.invoke(initSignModel).test {
|
||||
assertEquals(initState, awaitItem())
|
||||
|
|
@ -68,7 +72,15 @@ internal class WcSignUseCaseDelegateTest {
|
|||
|
||||
@Test
|
||||
fun `success sign, keep flow running`() = runTest {
|
||||
every { finalActionCollector.onSign } returns successSign
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {
|
||||
override suspend fun SignCollector<TestSignModel>.onSign(state: WcSignState<TestSignModel>) {
|
||||
successSign(state)
|
||||
}
|
||||
}
|
||||
val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
|
||||
useCase.invoke(initModel = initSignModel).test {
|
||||
assertEquals(initState, awaitItem())
|
||||
|
|
@ -82,7 +94,15 @@ internal class WcSignUseCaseDelegateTest {
|
|||
@Test
|
||||
fun `failed sign, keep flow running`() = runTest {
|
||||
val failedResult = signing.toResult(testException.left())
|
||||
every { finalActionCollector.onSign } returns failedSign
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {
|
||||
override suspend fun SignCollector<TestSignModel>.onSign(state: WcSignState<TestSignModel>) {
|
||||
failedSign(state)
|
||||
}
|
||||
}
|
||||
val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
|
||||
useCase.invoke(initSignModel).test {
|
||||
assertEquals(initState, awaitItem())
|
||||
|
|
@ -97,10 +117,16 @@ internal class WcSignUseCaseDelegateTest {
|
|||
fun `failed sign and catch unknown exception`() = runTest {
|
||||
val exception = RuntimeException("asd")
|
||||
val expectedErrorState = signing.toResult(exception.left())
|
||||
every { finalActionCollector.onSign } returns {
|
||||
delay(2)
|
||||
throw exception
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {
|
||||
override suspend fun SignCollector<TestSignModel>.onSign(state: WcSignState<TestSignModel>) {
|
||||
delay(2)
|
||||
throw exception
|
||||
}
|
||||
}
|
||||
val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
|
||||
useCase.invoke(initSignModel).test {
|
||||
assertEquals(initState, awaitItem())
|
||||
|
|
@ -113,10 +139,16 @@ internal class WcSignUseCaseDelegateTest {
|
|||
|
||||
@Test
|
||||
fun `interrupt signing and complete flow on cancel call`() = runTest {
|
||||
every { finalActionCollector.onSign } returns {
|
||||
delay(5)
|
||||
emit(result)
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {
|
||||
override suspend fun SignCollector<TestSignModel>.onSign(state: WcSignState<TestSignModel>) {
|
||||
delay(5)
|
||||
emit(result)
|
||||
}
|
||||
}
|
||||
val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
|
||||
useCase.invoke(initSignModel).test {
|
||||
assertEquals(initState, awaitItem())
|
||||
|
|
@ -135,13 +167,19 @@ internal class WcSignUseCaseDelegateTest {
|
|||
val startLoading2 = WcSignState(TestSignModel("startLoading 2"), WcSignStep.Signing)
|
||||
val expectedSignResult = result
|
||||
|
||||
every { finalActionCollector.onSign } returns {
|
||||
// should emit single time in this test
|
||||
emit(if (count % 2 == 0) startLoading else startLoading2)
|
||||
count = count.inc()
|
||||
delay(10)
|
||||
emit(expectedSignResult)
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {
|
||||
override suspend fun SignCollector<TestSignModel>.onSign(state: WcSignState<TestSignModel>) {
|
||||
// should emit single time in this test
|
||||
emit(if (count % 2 == 0) startLoading else startLoading2)
|
||||
count = count.inc()
|
||||
delay(10)
|
||||
emit(expectedSignResult)
|
||||
}
|
||||
}
|
||||
val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
|
||||
useCase.invoke(initSignModel).test {
|
||||
useCase.sign()
|
||||
|
|
@ -177,14 +215,24 @@ internal class WcSignUseCaseDelegateTest {
|
|||
domainStep = WcSignStep.PreSign,
|
||||
)
|
||||
|
||||
every { finalActionCollector.onSign } returns {
|
||||
delay(6)
|
||||
emit(failedSign)
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {
|
||||
override suspend fun SignCollector<TestSignModel>.onSign(state: WcSignState<TestSignModel>) {
|
||||
delay(6)
|
||||
emit(failedSign)
|
||||
}
|
||||
}
|
||||
|
||||
every { middleActionCollector.onMiddleAction } returns { currentState, middleAction ->
|
||||
emit(currentState.signModel.copy(testStr = middleAction.newTestStr))
|
||||
middleActionCollector = object : MiddleActionCollector<TestMiddleAction, TestSignModel> {
|
||||
override suspend fun FlowCollector<TestSignModel>.onMiddleAction(
|
||||
signModel: TestSignModel,
|
||||
middleAction: TestMiddleAction,
|
||||
) {
|
||||
emit(signModel.copy(testStr = middleAction.newTestStr))
|
||||
}
|
||||
}
|
||||
val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
|
||||
useCase.invoke(initSignModel).test {
|
||||
delay(2)
|
||||
|
|
@ -214,11 +262,24 @@ internal class WcSignUseCaseDelegateTest {
|
|||
val expectedFirst = initState.copy(signModel = firstTextMode)
|
||||
val expectedSecond = initState.copy(signModel = TestSignModel(TestMiddleAction.Two().newTestStr))
|
||||
|
||||
every { finalActionCollector.onSign } returns successSign
|
||||
every { middleActionCollector.onMiddleAction } returns { currentState, middleAction ->
|
||||
emit(currentState.signModel.copy(testStr = middleAction.newTestStr))
|
||||
delay(4)
|
||||
finalActionCollector = object : FinalActionCollector<TestSignModel> {
|
||||
override suspend fun SignCollector<TestSignModel>.onSign(state: WcSignState<TestSignModel>) {
|
||||
successSign(state)
|
||||
}
|
||||
}
|
||||
middleActionCollector = object : MiddleActionCollector<TestMiddleAction, TestSignModel> {
|
||||
override suspend fun FlowCollector<TestSignModel>.onMiddleAction(
|
||||
signModel: TestSignModel,
|
||||
middleAction: TestMiddleAction,
|
||||
) {
|
||||
emit(signModel.copy(testStr = middleAction.newTestStr))
|
||||
delay(4)
|
||||
}
|
||||
}
|
||||
val useCase = WcSignUseCaseDelegate(
|
||||
finalActionCollector = finalActionCollector,
|
||||
middleActionCollector = middleActionCollector,
|
||||
)
|
||||
|
||||
useCase.invoke(initSignModel).test {
|
||||
assertEquals(initState, awaitItem())
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ package com.tangem.domain.transaction.usecase
|
|||
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.demo.DemoTransactionSender
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.error.mapToFeeError
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
|
|
@ -25,6 +24,32 @@ class GetFeeUseCase(
|
|||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val demoConfig: DemoConfig,
|
||||
) {
|
||||
suspend operator fun invoke(userWallet: UserWallet, network: Network, transactionData: TransactionData) = either {
|
||||
catch(
|
||||
block = {
|
||||
val transactionSender = if (demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)) {
|
||||
demoTransactionSender(userWallet, network)
|
||||
} else {
|
||||
walletManagersFacade.getOrCreateWalletManager(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = network,
|
||||
) as? TransactionSender
|
||||
}
|
||||
val result = transactionSender?.getFee(transactionData = transactionData)
|
||||
?: error("Fee is null")
|
||||
|
||||
val maybeFee = when (result) {
|
||||
is Result.Success -> result.data
|
||||
is Result.Failure -> raise(result.mapToFeeError())
|
||||
}
|
||||
maybeFee
|
||||
},
|
||||
catch = {
|
||||
raise(GetFeeError.DataError(it))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
amount: BigDecimal,
|
||||
destination: String,
|
||||
|
|
@ -36,7 +61,7 @@ class GetFeeUseCase(
|
|||
val amountData = convertCryptoCurrencyToAmount(cryptoCurrency, amount)
|
||||
|
||||
val result = if (demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)) {
|
||||
demoTransactionSender(userWallet, cryptoCurrency).getFee(
|
||||
demoTransactionSender(userWallet, cryptoCurrency.network).getFee(
|
||||
amount = amountData,
|
||||
destination = destination,
|
||||
)
|
||||
|
|
@ -61,13 +86,9 @@ class GetFeeUseCase(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun demoTransactionSender(
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): DemoTransactionSender {
|
||||
private suspend fun demoTransactionSender(userWallet: UserWallet, network: Network): DemoTransactionSender {
|
||||
return DemoTransactionSender(
|
||||
walletManagersFacade
|
||||
.getOrCreateWalletManager(userWallet.walletId, cryptoCurrency.network)
|
||||
walletManagersFacade.getOrCreateWalletManager(userWallet.walletId, network)
|
||||
?: error("WalletManager is null"),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.domain.walletconnect.usecase
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.walletconnect.model.WcSession
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
|
||||
|
|
@ -10,4 +11,8 @@ interface WcMethodUseCase : WcUseCase {
|
|||
val session: WcSession
|
||||
val rawSdkRequest: WcSdkSessionRequest
|
||||
val network: Network
|
||||
}
|
||||
|
||||
interface WcMutableFee {
|
||||
fun updateFee(fee: Fee)
|
||||
}
|
||||
|
|
@ -1,24 +1,42 @@
|
|||
package com.tangem.domain.walletconnect.usecase.ethereum
|
||||
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.walletconnect.model.WcSession
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
|
||||
import com.tangem.domain.walletconnect.usecase.WcMutableFee
|
||||
import com.tangem.domain.walletconnect.usecase.sign.WcSignUseCase
|
||||
|
||||
interface WcEthSendTransactionUseCase :
|
||||
WcSignUseCase,
|
||||
WcSignUseCase.SimpleRun<TransactionData> {
|
||||
WcSignUseCase.SimpleRun<WcEthTransaction>,
|
||||
WcMutableFee {
|
||||
|
||||
fun updateFee(fee: TransactionFee)
|
||||
override val session: WcSession
|
||||
override val rawSdkRequest: WcSdkSessionRequest
|
||||
override val network: Network
|
||||
|
||||
override fun sign()
|
||||
override fun cancel()
|
||||
override fun updateFee(fee: Fee)
|
||||
}
|
||||
|
||||
interface WcEthSignTransactionUseCase :
|
||||
WcSignUseCase,
|
||||
WcSignUseCase.SimpleRun<TransactionData> {
|
||||
WcSignUseCase.SimpleRun<WcEthTransaction>,
|
||||
WcMutableFee {
|
||||
|
||||
fun updateFee(fee: TransactionFee)
|
||||
override val session: WcSession
|
||||
override val rawSdkRequest: WcSdkSessionRequest
|
||||
override val network: Network
|
||||
|
||||
override fun sign()
|
||||
override fun cancel()
|
||||
override fun updateFee(fee: Fee)
|
||||
}
|
||||
|
||||
data class WcEthTransaction(
|
||||
val isFeeByDap: Boolean,
|
||||
val fee: TransactionFee,
|
||||
val dAppFee: Fee.Ethereum.Legacy?,
|
||||
val transactionData: TransactionData.Uncompiled,
|
||||
)
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
# https://github.com/tangem/tangem-sdk-android/
|
||||
# https://github.com/tangem/vico
|
||||
|
||||
tangemBlockchainSdk = "develop-1040"
|
||||
tangemBlockchainSdk = "develop-1041"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-455"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue