From a2b440444ee0bbde5620adf999a26b92eb659926 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 22 Apr 2025 16:28:48 +0700 Subject: [PATCH] Updated on 2026-08-14 --- .../DefaultWcEthMessageSignUseCase.kt | 10 +- .../DefaultWcEthSendTransactionUseCase.kt | 33 +++-- .../DefaultWcEthSignTransactionUseCase.kt | 43 +++--- .../ethereum/EthTransactionParamsConverter.kt | 25 ++++ .../network/ethereum/WcEthTxHelper.kt | 58 ++++++++ .../walletconnect/sign/BaseWcSignUseCase.kt | 15 +- .../sign/WcSignUseCaseDelegate.kt | 4 +- .../WcSignUseCaseDelegateTest.kt | 133 +++++++++++++----- .../transaction/usecase/GetFeeUseCase.kt | 41 ++++-- .../domain/walletconnect/usecase/WcUseCase.kt | 5 + .../ethereum/WcEthTransactionUseCase.kt | 32 ++++- gradle/tangem_dependencies.toml | 2 +- 12 files changed, 300 insertions(+), 101 deletions(-) create mode 100644 data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/EthTransactionParamsConverter.kt create mode 100644 data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthTxHelper.kt diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthMessageSignUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthMessageSignUseCase.kt index 8421ccb613..bbbd62d234 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthMessageSignUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthMessageSignUseCase.kt @@ -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(), WcEthMessageSignUseCase { - override val onSign: OnSign = collector@{ state -> + override suspend fun SignCollector.onSign( + state: WcSignState, + ) { 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, diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSendTransactionUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSendTransactionUseCase.kt index 76e1b410de..c923e955fd 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSendTransactionUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSendTransactionUseCase.kt @@ -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(), +) : BaseWcSignUseCase(), WcEthSendTransactionUseCase { - override val onSign: OnSign = collector@{ state -> - val hash = sendTransaction(state.signModel, wallet, network) + private val converter = EthTransactionParamsConverter(context) + + override suspend fun SignCollector.onSign(state: WcSignState) { + 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> { - method - TODO("Not yet implemented") + override fun invoke(): Flow> = flow { + val ethTransaction = converter.convert(method.transaction) ?: return@flow + emitAll(delegate.invoke(ethTransaction)) } @AssistedFactory diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSignTransactionUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSignTransactionUseCase.kt index d8a01823c7..70b1c7b3a3 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSignTransactionUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSignTransactionUseCase.kt @@ -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(), +) : BaseWcSignUseCase(), WcEthSignTransactionUseCase { - override val onSign: OnSign = collector@{ state -> - val hash = prepareForSend(state.signModel, wallet, network) + private val converter = EthTransactionParamsConverter(context) + + override suspend fun SignCollector.onSign(state: WcSignState) { + 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.onMiddleAction(signModel: WcEthTransaction, fee: Fee) { + val newState = signModel + .copy(transactionData = signModel.transactionData.copy(fee = fee)) + emit(newState) } - override fun invoke(): Flow> { - method - TODO("Not yet implemented") + override fun updateFee(fee: Fee) { + middleAction(fee) + } + + override fun invoke(): Flow> = flow { + val ethTransaction = converter.convert(method.transaction) ?: return@flow + emitAll(delegate.invoke(ethTransaction)) } @AssistedFactory diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/EthTransactionParamsConverter.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/EthTransactionParamsConverter.kt new file mode 100644 index 0000000000..ac63abc8f8 --- /dev/null +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/EthTransactionParamsConverter.kt @@ -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 { + + 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, + ) + } +} \ No newline at end of file diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthTxHelper.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthTxHelper.kt new file mode 100644 index 0000000000..bc1f5e26c5 --- /dev/null +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthTxHelper.kt @@ -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(), + ), + ) + } +} \ No newline at end of file diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/BaseWcSignUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/BaseWcSignUseCase.kt index d4e8696371..8967ae0706 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/BaseWcSignUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/BaseWcSignUseCase.kt @@ -31,7 +31,7 @@ internal abstract class BaseWcSignUseCase : ) } - override val onCancel: suspend (currentState: WcSignState) -> Unit = { + override suspend fun onCancel(currentState: WcSignState) { defaultReject() } @@ -46,14 +46,14 @@ internal abstract class BaseWcSignUseCase : internal interface MiddleActionCollector { - val onMiddleAction: OnMiddle get() = { _, _ -> } + suspend fun FlowCollector.onMiddleAction(signModel: SignModel, middleAction: MiddleAction) {} } internal interface FinalActionCollector { - val onSign: OnSign get() = {} + suspend fun SignCollector.onSign(state: WcSignState) {} - val onCancel: OnCancel get() = {} + suspend fun onCancel(state: WcSignState) {} } internal class WcMethodUseCaseContext( @@ -62,9 +62,4 @@ internal class WcMethodUseCaseContext( val network: Network, ) -internal typealias OnSign = - suspend FlowCollector>.(state: WcSignState) -> Unit -internal typealias OnCancel = - suspend (currentState: WcSignState) -> Unit -internal typealias OnMiddle = - suspend FlowCollector.(currentState: WcSignState, middleAction: MiddleAction) -> Unit \ No newline at end of file +internal typealias SignCollector = FlowCollector> \ No newline at end of file diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/WcSignUseCaseDelegate.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/WcSignUseCaseDelegate.kt index c84bc39ac7..89d8bc1097 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/WcSignUseCaseDelegate.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/WcSignUseCaseDelegate.kt @@ -42,7 +42,7 @@ internal class WcSignUseCaseDelegate( 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( .transformLatest { finalAction -> when (finalAction) { Action.Cancel -> { - onCancel.invoke(state.value) + onCancel(state.value) channel.close() } Action.Sign -> { diff --git a/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/WcSignUseCaseDelegateTest.kt b/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/WcSignUseCaseDelegateTest.kt index e80bd9a4f8..39aaa7b68c 100644 --- a/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/WcSignUseCaseDelegateTest.kt +++ b/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/WcSignUseCaseDelegateTest.kt @@ -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>() - private val finalActionCollector = mockk>() - private val useCase = WcSignUseCaseDelegate( - finalActionCollector = finalActionCollector, - middleActionCollector = middleActionCollector, - ) + private var middleActionCollector: MiddleActionCollector = + object : MiddleActionCollector {} + private var finalActionCollector: FinalActionCollector = + object : FinalActionCollector {} 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 {} + finalActionCollector = object : FinalActionCollector {} } @Test fun `invoke and keep flow running`() = runTest { - every { finalActionCollector.onSign } returns successSign + finalActionCollector = object : FinalActionCollector { + override suspend fun SignCollector.onSign(state: WcSignState) { + 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 { + override suspend fun SignCollector.onSign(state: WcSignState) { + 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 { + override suspend fun SignCollector.onSign(state: WcSignState) { + 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 { + override suspend fun SignCollector.onSign(state: WcSignState) { + 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 { + override suspend fun SignCollector.onSign(state: WcSignState) { + 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 { + override suspend fun SignCollector.onSign(state: WcSignState) { + // 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 { + override suspend fun SignCollector.onSign(state: WcSignState) { + delay(6) + emit(failedSign) + } } - - every { middleActionCollector.onMiddleAction } returns { currentState, middleAction -> - emit(currentState.signModel.copy(testStr = middleAction.newTestStr)) + middleActionCollector = object : MiddleActionCollector { + override suspend fun FlowCollector.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 { + override suspend fun SignCollector.onSign(state: WcSignState) { + successSign(state) + } } + middleActionCollector = object : MiddleActionCollector { + override suspend fun FlowCollector.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()) diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetFeeUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetFeeUseCase.kt index c370ac644d..ed841119c1 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetFeeUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetFeeUseCase.kt @@ -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"), ) } diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/WcUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/WcUseCase.kt index 1aff7cea04..fbe655766a 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/WcUseCase.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/WcUseCase.kt @@ -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) } \ No newline at end of file diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthTransactionUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthTransactionUseCase.kt index 7df50defdc..48f74153de 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthTransactionUseCase.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthTransactionUseCase.kt @@ -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 { + WcSignUseCase.SimpleRun, + 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 { + WcSignUseCase.SimpleRun, + 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, ) \ No newline at end of file diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index bcba22609f..0c3b257143 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -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 ^