Updated on 2026-08-14
This commit is contained in:
commit
a335e8d8f4
21 changed files with 541 additions and 63 deletions
|
|
@ -155,6 +155,7 @@ dependencies {
|
|||
implementation(projects.domain.walletManager)
|
||||
implementation(projects.domain.walletManager.models)
|
||||
implementation(projects.domain.yieldSupply)
|
||||
implementation(projects.domain.blockaid)
|
||||
|
||||
implementation(projects.common)
|
||||
implementation(projects.common.routing)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.blockaid.BlockAidGasEstimate
|
||||
import com.tangem.domain.transaction.FeeRepository
|
||||
import com.tangem.domain.transaction.error.FeeErrorResolver
|
||||
import com.tangem.domain.yield.supply.YieldSupplyTransactionRepository
|
||||
|
|
@ -42,10 +43,12 @@ internal object YieldSupplyDomainModule {
|
|||
fun provideYieldSupplyEstimateEnterFeeUseCase(
|
||||
feeRepository: FeeRepository,
|
||||
feeErrorResolver: FeeErrorResolver,
|
||||
blockAidGasEstimate: BlockAidGasEstimate,
|
||||
): YieldSupplyEstimateEnterFeeUseCase {
|
||||
return YieldSupplyEstimateEnterFeeUseCase(
|
||||
feeRepository = feeRepository,
|
||||
feeErrorResolver = feeErrorResolver,
|
||||
blockAidGasEstimate = blockAidGasEstimate,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.datasource.api.common.blockaid
|
||||
|
||||
import com.tangem.datasource.api.common.blockaid.models.request.DomainScanRequest
|
||||
import com.tangem.datasource.api.common.blockaid.models.request.EvmTransactionBulkScanRequest
|
||||
import com.tangem.datasource.api.common.blockaid.models.request.EvmTransactionScanRequest
|
||||
import com.tangem.datasource.api.common.blockaid.models.request.SolanaTransactionScanRequest
|
||||
import com.tangem.datasource.api.common.blockaid.models.response.DomainScanResponse
|
||||
import com.tangem.datasource.api.common.blockaid.models.response.GasEstimationResponse
|
||||
import com.tangem.datasource.api.common.blockaid.models.response.SolanaTransactionResponse
|
||||
import com.tangem.datasource.api.common.blockaid.models.response.TransactionScanResponse
|
||||
import retrofit2.http.Body
|
||||
|
|
@ -19,4 +21,7 @@ interface BlockAidApi {
|
|||
|
||||
@POST("solana/message/scan")
|
||||
suspend fun scanSolanaMessage(@Body request: SolanaTransactionScanRequest): SolanaTransactionResponse
|
||||
|
||||
@POST("evm/transaction-bulk/scan")
|
||||
suspend fun scanEvmTransactionBulk(@Body request: EvmTransactionBulkScanRequest): List<GasEstimationResponse>
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.datasource.api.common.blockaid.models.request
|
||||
|
||||
enum class BlockAidScanOptions(val value: String) {
|
||||
Simulation("simulation"),
|
||||
Validation("validation"),
|
||||
GasEstimation("gas_estimation"),
|
||||
}
|
||||
|
|
@ -14,9 +14,25 @@ data class EvmTransactionScanRequest(
|
|||
@Json(name = "metadata") val metadata: TransactionMetadata,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class EvmTransactionBulkScanRequest(
|
||||
@Json(name = "chain") val chain: String,
|
||||
@Json(name = "options") val options: List<String>,
|
||||
@Json(name = "metadata") val metadata: TransactionMetadata,
|
||||
@Json(name = "data") val data: List<Data>,
|
||||
@Json(name = "aggregated") val aggregated: Boolean = false,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RpcData(
|
||||
@Json(name = "jsonrpc") val jsonrpc: String = "2.0",
|
||||
@Json(name = "method") val method: String,
|
||||
@Json(name = "params") val params: List<Map<String, String>>,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Data(
|
||||
@Json(name = "from") val from: String,
|
||||
@Json(name = "to") val to: String,
|
||||
@Json(name = "data") val data: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.datasource.api.common.blockaid.models.response
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GasEstimationResponse(
|
||||
@Json(name = "gas_estimation") val gasEstimation: GasEstimationItem,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GasEstimationItem(
|
||||
@Json(name = "estimate") val estimate: String,
|
||||
)
|
||||
|
|
@ -12,6 +12,7 @@ android {
|
|||
dependencies {
|
||||
/* Project - Domain */
|
||||
implementation(projects.data.common)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.blockaid)
|
||||
implementation(projects.domain.blockaid.models)
|
||||
|
||||
|
|
@ -20,6 +21,7 @@ dependencies {
|
|||
|
||||
/* Project - Core */
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
|
||||
/* DI */
|
||||
implementation(deps.hilt.core)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.data.blockaid
|
||||
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.datasource.api.common.blockaid.models.request.BlockAidScanOptions
|
||||
import com.tangem.datasource.api.common.blockaid.models.request.Data
|
||||
import com.tangem.datasource.api.common.blockaid.models.request.EvmTransactionBulkScanRequest
|
||||
import com.tangem.datasource.api.common.blockaid.models.response.TransactionMetadata
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.blockchain.common.TransactionData as SDKTransactionData
|
||||
|
||||
internal class BlockAidEvmScanTransactionConverter(
|
||||
private val blockchain: Blockchain,
|
||||
) : Converter<List<SDKTransactionData.Uncompiled>, EvmTransactionBulkScanRequest> {
|
||||
|
||||
override fun convert(value: List<SDKTransactionData.Uncompiled>): EvmTransactionBulkScanRequest {
|
||||
return EvmTransactionBulkScanRequest(
|
||||
chain = blockchain.getChainId().toString(),
|
||||
options = listOf(BlockAidScanOptions.GasEstimation.value),
|
||||
metadata = TransactionMetadata(domain = "https://tangem.com"),
|
||||
data = value.map {
|
||||
Data(
|
||||
from = it.sourceAddress,
|
||||
to = it.destinationAddress,
|
||||
data = (it.extras as? EthereumTransactionExtras)?.callData?.dataHex.orEmpty(),
|
||||
)
|
||||
},
|
||||
aggregated = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,19 @@ package com.tangem.data.blockaid
|
|||
import com.domain.blockaid.models.dapp.CheckDAppResult
|
||||
import com.domain.blockaid.models.dapp.DAppData
|
||||
import com.domain.blockaid.models.transaction.CheckTransactionResult
|
||||
import com.domain.blockaid.models.transaction.GasEstimationResult
|
||||
import com.domain.blockaid.models.transaction.TransactionData
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.blockchain.common.TransactionData as SDKTransactionData
|
||||
|
||||
interface BlockAidRepository {
|
||||
|
||||
suspend fun verifyDAppDomain(data: DAppData): CheckDAppResult
|
||||
|
||||
suspend fun verifyTransaction(data: TransactionData): CheckTransactionResult
|
||||
|
||||
suspend fun getGasEstimation(
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
transactionDataList: List<SDKTransactionData.Uncompiled>,
|
||||
): GasEstimationResult
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.data.blockaid
|
||||
|
||||
import arrow.core.Either
|
||||
import com.domain.blockaid.models.transaction.GasEstimationResult
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.domain.blockaid.BlockAidGasEstimate
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import javax.inject.Inject
|
||||
|
||||
class DefaultBlockAidGasEstimate @Inject constructor(
|
||||
private val repository: BlockAidRepository,
|
||||
) : BlockAidGasEstimate {
|
||||
override suspend fun getGasEstimation(
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
transactionDataList: List<TransactionData.Uncompiled>,
|
||||
): Either<Throwable, GasEstimationResult> = Either.catch {
|
||||
repository.getGasEstimation(cryptoCurrency = cryptoCurrency, transactionDataList = transactionDataList)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,18 @@ package com.tangem.data.blockaid
|
|||
import com.domain.blockaid.models.dapp.CheckDAppResult
|
||||
import com.domain.blockaid.models.dapp.DAppData
|
||||
import com.domain.blockaid.models.transaction.CheckTransactionResult
|
||||
import com.domain.blockaid.models.transaction.GasEstimationResult
|
||||
import com.domain.blockaid.models.transaction.TransactionData
|
||||
import com.domain.blockaid.models.transaction.TransactionParams
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||
import com.tangem.data.blockaid.converters.GasEstimationResponseConverter
|
||||
import com.tangem.datasource.api.common.blockaid.BlockAidApi
|
||||
import com.tangem.datasource.api.common.blockaid.models.request.DomainScanRequest
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.tangem.blockchain.common.TransactionData as SDKTransactionData
|
||||
|
||||
internal class DefaultBlockAidRepository(
|
||||
private val api: BlockAidApi,
|
||||
|
|
@ -30,6 +36,17 @@ internal class DefaultBlockAidRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getGasEstimation(
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
transactionDataList: List<SDKTransactionData.Uncompiled>,
|
||||
): GasEstimationResult {
|
||||
val blockchain = cryptoCurrency.network.toBlockchain()
|
||||
return when {
|
||||
blockchain.isEvm() -> scanEvmTransactionBulk(blockchain, transactionDataList)
|
||||
else -> error("Gas estimation with BlockAid not supported by ${blockchain.fullName}")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun scanEvmTransaction(data: TransactionData): CheckTransactionResult =
|
||||
withContext(dispatchers.io) {
|
||||
val response = api.scanJsonRpc(mapper.mapToEvmRequest(data))
|
||||
|
|
@ -41,4 +58,15 @@ internal class DefaultBlockAidRepository(
|
|||
val response = api.scanSolanaMessage(mapper.mapToSolanaRequest(data))
|
||||
mapper.mapToDomain(response)
|
||||
}
|
||||
|
||||
private suspend fun scanEvmTransactionBulk(
|
||||
blockchain: Blockchain,
|
||||
transactionDataList: List<SDKTransactionData.Uncompiled>,
|
||||
): GasEstimationResult = withContext(dispatchers.io) {
|
||||
val response = api.scanEvmTransactionBulk(
|
||||
BlockAidEvmScanTransactionConverter(blockchain).convert(transactionDataList),
|
||||
)
|
||||
|
||||
GasEstimationResponseConverter.convert(response)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.data.blockaid.converters
|
||||
|
||||
import com.domain.blockaid.models.transaction.GasEstimationResult
|
||||
import com.tangem.blockchain.extensions.hexToBigInteger
|
||||
import com.tangem.datasource.api.common.blockaid.models.response.GasEstimationResponse
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal object GasEstimationResponseConverter : Converter<List<GasEstimationResponse>, GasEstimationResult> {
|
||||
override fun convert(value: List<GasEstimationResponse>): GasEstimationResult {
|
||||
return GasEstimationResult(
|
||||
estimatedGasList = value.map { it.gasEstimation.estimate.hexToBigInteger() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.data.blockaid.di
|
||||
|
||||
import com.tangem.data.blockaid.DefaultBlockAidGasEstimate
|
||||
import com.tangem.data.blockaid.DefaultBlockAidVerifier
|
||||
import com.tangem.domain.blockaid.BlockAidGasEstimate
|
||||
import com.tangem.domain.blockaid.BlockAidVerifier
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
|
@ -15,4 +17,8 @@ interface BlockAidDataModule {
|
|||
@Binds
|
||||
@Singleton
|
||||
fun bindVerifier(verifier: DefaultBlockAidVerifier): BlockAidVerifier
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindBlockAidGasEstimate(gasEstimate: DefaultBlockAidGasEstimate): BlockAidGasEstimate
|
||||
}
|
||||
|
|
@ -1,7 +1,13 @@
|
|||
package com.tangem.data.transaction
|
||||
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||
import com.tangem.blockchain.blockchains.ethereum.eip1559.isSupportEIP1559
|
||||
import com.tangem.blockchain.blockchains.ethereum.network.EthereumFeeHistory
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||
|
|
@ -12,6 +18,8 @@ import com.tangem.domain.models.network.Network
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.transaction.FeeRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
internal class DefaultFeeRepository(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
|
|
@ -22,6 +30,53 @@ internal class DefaultFeeRepository(
|
|||
return networkId.toBlockchain().isFeeApproximate(amountType)
|
||||
}
|
||||
|
||||
override suspend fun getEthereumFeeWithoutGas(
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Fee.Ethereum {
|
||||
val walletManager = walletManagersFacade.getOrCreateWalletManager(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = cryptoCurrency.network,
|
||||
)
|
||||
|
||||
val blockchain = cryptoCurrency.network.toBlockchain()
|
||||
|
||||
val ethereumWalletManager = walletManager as? EthereumWalletManager
|
||||
?: error("Not supported for ${cryptoCurrency.network}")
|
||||
|
||||
val fee = if (blockchain.isSupportEIP1559) {
|
||||
val gasHistory = when (val gasHistory = ethereumWalletManager.getGasHistory()) {
|
||||
is Result.Failure -> throw gasHistory.error
|
||||
is Result.Success -> gasHistory.data
|
||||
}
|
||||
|
||||
val marketPriorityFee = when (gasHistory) {
|
||||
is EthereumFeeHistory.Common -> gasHistory.marketPriorityFee
|
||||
is EthereumFeeHistory.Fallback -> gasHistory.gasPrice.toBigDecimal() * MULTIPLIER_GAS_PRICE_NORMAL_FEE
|
||||
}
|
||||
|
||||
val maxFeePerGas = gasHistory.baseFee * MULTIPLIER_GAS_PRICE_NORMAL_FEE + marketPriorityFee
|
||||
|
||||
getEthEip1559Fee(
|
||||
maxFeePerGas = maxFeePerGas.toBigInteger(),
|
||||
priorityFee = marketPriorityFee.toBigInteger(),
|
||||
blockchain = blockchain,
|
||||
)
|
||||
} else {
|
||||
val gasPrice = when (val gasPrice = ethereumWalletManager.getGasPrice()) {
|
||||
is Result.Failure -> throw gasPrice.error
|
||||
is Result.Success -> gasPrice.data
|
||||
}
|
||||
|
||||
getEthLegacyFee(
|
||||
gasPrice = gasPrice,
|
||||
blockchain = blockchain,
|
||||
)
|
||||
}
|
||||
|
||||
return fee
|
||||
}
|
||||
|
||||
override suspend fun calculateFee(
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
|
|
@ -54,4 +109,37 @@ internal class DefaultFeeRepository(
|
|||
?: error("WalletManager is null"),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getEthLegacyFee(gasPrice: BigInteger, blockchain: Blockchain): Fee.Ethereum.Legacy {
|
||||
val amount = Amount(
|
||||
value = BigDecimal.ZERO,
|
||||
blockchain = blockchain,
|
||||
)
|
||||
return Fee.Ethereum.Legacy(
|
||||
amount = amount,
|
||||
gasLimit = BigInteger.ZERO,
|
||||
gasPrice = gasPrice,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getEthEip1559Fee(
|
||||
maxFeePerGas: BigInteger,
|
||||
priorityFee: BigInteger,
|
||||
blockchain: Blockchain,
|
||||
): Fee.Ethereum.EIP1559 {
|
||||
val amount = Amount(
|
||||
value = BigDecimal.ZERO,
|
||||
blockchain = blockchain,
|
||||
)
|
||||
return Fee.Ethereum.EIP1559(
|
||||
amount = amount,
|
||||
gasLimit = BigInteger.ZERO,
|
||||
maxFeePerGas = maxFeePerGas,
|
||||
priorityFee = priorityFee,
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val MULTIPLIER_GAS_PRICE_NORMAL_FEE = "1.2".toBigDecimal() // 120%
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,23 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.domain.blockaid"
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
/* Project - Domain */
|
||||
/** Project - Domain */
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.blockaid.models)
|
||||
|
||||
/* Other */
|
||||
/** Tangem SDK */
|
||||
implementation(tangemDeps.blockchain)
|
||||
|
||||
|
||||
/** Other */
|
||||
implementation(deps.moshi.adapters)
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.domain.blockaid.models.transaction
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
data class GasEstimationResult(
|
||||
val estimatedGasList: List<BigInteger>,
|
||||
)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.domain.blockaid
|
||||
|
||||
import arrow.core.Either
|
||||
import com.domain.blockaid.models.transaction.GasEstimationResult
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
||||
interface BlockAidGasEstimate {
|
||||
|
||||
suspend fun getGasEstimation(
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
transactionDataList: List<TransactionData.Uncompiled>,
|
||||
): Either<Throwable, GasEstimationResult>
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.domain.transaction
|
|||
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
|
|
@ -18,4 +19,6 @@ interface FeeRepository {
|
|||
cryptoCurrency: CryptoCurrency,
|
||||
transactionData: TransactionData,
|
||||
): TransactionFee
|
||||
|
||||
suspend fun getEthereumFeeWithoutGas(userWallet: UserWallet, cryptoCurrency: CryptoCurrency): Fee.Ethereum
|
||||
}
|
||||
|
|
@ -18,12 +18,15 @@ dependencies {
|
|||
implementation(projects.domain.transaction.models)
|
||||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.blockaid.models)
|
||||
implementation(projects.domain.blockaid)
|
||||
|
||||
/** Tandem SDK */
|
||||
implementation(tangemDeps.blockchain)
|
||||
|
||||
/** Other */
|
||||
implementation(deps.arrow.core)
|
||||
implementation(deps.timber)
|
||||
|
||||
/** tests */
|
||||
testImplementation(projects.common.test)
|
||||
|
|
|
|||
|
|
@ -5,23 +5,85 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
|||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyEnterCallData
|
||||
import com.tangem.domain.blockaid.BlockAidGasEstimate
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.transaction.FeeRepository
|
||||
import com.tangem.domain.transaction.error.FeeErrorResolver
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.utils.extensions.isSingleItem
|
||||
import timber.log.Timber
|
||||
import java.math.BigInteger
|
||||
|
||||
class YieldSupplyEstimateEnterFeeUseCase(
|
||||
private val feeRepository: FeeRepository,
|
||||
private val feeErrorResolver: FeeErrorResolver,
|
||||
private val blockAidGasEstimate: BlockAidGasEstimate,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
transactionDataList: List<TransactionData.Uncompiled>,
|
||||
): Either<GetFeeError, List<TransactionData.Uncompiled>> = Either.catch {
|
||||
val withCalculatedFee = transactionDataList.filter {
|
||||
if (transactionDataList.isSingleItem()) {
|
||||
transactionDataList.map { transaction ->
|
||||
transaction.copy(
|
||||
fee = feeRepository.calculateFee(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionData = transaction,
|
||||
).normal,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val estimatedFees = estimateFeeWithBlockAid(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = transactionDataList,
|
||||
)
|
||||
|
||||
if (estimatedFees.isNullOrEmpty()) {
|
||||
// Fallback in case block aid returns error
|
||||
estimateFeeWithStatic(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = transactionDataList,
|
||||
)
|
||||
} else {
|
||||
estimatedFees
|
||||
}
|
||||
}
|
||||
}.mapLeft(feeErrorResolver::resolve)
|
||||
|
||||
private suspend fun estimateFeeWithBlockAid(
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
transactionDataList: List<TransactionData.Uncompiled>,
|
||||
): List<TransactionData.Uncompiled>? {
|
||||
val estimatedFees = blockAidGasEstimate.getGasEstimation(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = transactionDataList,
|
||||
).onLeft(Timber::e).getOrNull() ?: return null
|
||||
|
||||
if (estimatedFees.estimatedGasList.isEmpty()) return null
|
||||
|
||||
val fee = feeRepository.getEthereumFeeWithoutGas(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
)
|
||||
|
||||
return transactionDataList.zip(estimatedFees.estimatedGasList) { transaction, estimatedGas ->
|
||||
transaction.copy(fee = fee.fixFee(cryptoCurrency, estimatedGas))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun estimateFeeWithStatic(
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
transactionDataList: List<TransactionData.Uncompiled>,
|
||||
): List<TransactionData.Uncompiled> {
|
||||
val withCalculatedFees = transactionDataList.filter {
|
||||
(it.extras as? EthereumTransactionExtras)?.callData !is EthereumYieldSupplyEnterCallData
|
||||
}.map { transaction ->
|
||||
transaction.copy(
|
||||
|
|
@ -33,38 +95,30 @@ class YieldSupplyEstimateEnterFeeUseCase(
|
|||
)
|
||||
}
|
||||
|
||||
val withEstimatedCalculatedFee = transactionDataList.filter {
|
||||
val calculatedFee = withCalculatedFees.firstOrNull()?.fee ?: error("Must be any calculated fee")
|
||||
|
||||
val withEstimatedFees = transactionDataList.filter {
|
||||
(it.extras as? EthereumTransactionExtras)?.callData is EthereumYieldSupplyEnterCallData
|
||||
}.map { transaction ->
|
||||
if (transactionDataList.isSingleItem()) {
|
||||
transaction.copy(
|
||||
fee = feeRepository.calculateFee(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionData = transaction,
|
||||
).normal,
|
||||
)
|
||||
} else {
|
||||
transaction.copy(fee = withCalculatedFee.firstOrNull()?.fee?.fixFee(cryptoCurrency))
|
||||
}
|
||||
transaction.copy(fee = calculatedFee.fixFee(cryptoCurrency, ETHEREUM_CONSTANT_GAS_LIMIT))
|
||||
}
|
||||
|
||||
// Transactions order must be preserved
|
||||
withCalculatedFee + withEstimatedCalculatedFee
|
||||
}.mapLeft(feeErrorResolver::resolve)
|
||||
// First return calculated fees then estimated
|
||||
return withCalculatedFees + withEstimatedFees
|
||||
}
|
||||
|
||||
private fun Fee.fixFee(cryptoCurrency: CryptoCurrency) = when (this) {
|
||||
private fun Fee.fixFee(cryptoCurrency: CryptoCurrency, gasLimit: BigInteger) = when (this) {
|
||||
is Fee.Ethereum.Legacy -> copy(
|
||||
gasLimit = ETHEREUM_CONSTANT_GAS_LIMIT,
|
||||
gasLimit = gasLimit,
|
||||
amount = amount.copy(
|
||||
value = gasPrice.multiply(ETHEREUM_CONSTANT_GAS_LIMIT)
|
||||
value = gasPrice.multiply(gasLimit)
|
||||
.toBigDecimal().movePointLeft(cryptoCurrency.decimals),
|
||||
),
|
||||
)
|
||||
is Fee.Ethereum.EIP1559 -> copy(
|
||||
gasLimit = ETHEREUM_CONSTANT_GAS_LIMIT,
|
||||
gasLimit = gasLimit,
|
||||
amount = amount.copy(
|
||||
value = maxFeePerGas.multiply(ETHEREUM_CONSTANT_GAS_LIMIT)
|
||||
value = maxFeePerGas.multiply(gasLimit)
|
||||
.toBigDecimal().movePointLeft(cryptoCurrency.decimals),
|
||||
),
|
||||
)
|
||||
|
|
@ -73,6 +127,6 @@ class YieldSupplyEstimateEnterFeeUseCase(
|
|||
|
||||
private companion object {
|
||||
// Using constant gas limit to avoid fee calculation errors when contract address is not deployed yet
|
||||
val ETHEREUM_CONSTANT_GAS_LIMIT = 350_000.toBigInteger()
|
||||
val ETHEREUM_CONSTANT_GAS_LIMIT = 500_000.toBigInteger()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.domain.yield.supply
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.right
|
||||
import com.domain.blockaid.models.transaction.GasEstimationResult
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
|
|
@ -10,6 +12,7 @@ import com.tangem.blockchain.common.smartcontract.SmartContractCallDataProviderF
|
|||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.yieldsupply.YieldSupplyContractCallDataProviderFactory
|
||||
import com.tangem.domain.blockaid.BlockAidGasEstimate
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
|
|
@ -17,9 +20,7 @@ import com.tangem.domain.transaction.FeeRepository
|
|||
import com.tangem.domain.transaction.error.FeeErrorResolver
|
||||
import com.tangem.domain.utils.convertToSdkAmount
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyEstimateEnterFeeUseCase
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.*
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
|
@ -30,7 +31,8 @@ import java.math.BigInteger
|
|||
class YieldSupplyEstimateEnterFeeUseCaseTest {
|
||||
private val feeRepository: FeeRepository = mockk()
|
||||
private val feeErrorResolver: FeeErrorResolver = mockk()
|
||||
private val useCase = YieldSupplyEstimateEnterFeeUseCase(feeRepository, feeErrorResolver)
|
||||
private val blockAidGasEstimate: BlockAidGasEstimate = mockk()
|
||||
private val useCase = YieldSupplyEstimateEnterFeeUseCase(feeRepository, feeErrorResolver, blockAidGasEstimate)
|
||||
|
||||
private val userWallet: UserWallet = mockk()
|
||||
private val cryptoCurrency: CryptoCurrency = mockk(relaxed = true) {
|
||||
|
|
@ -72,45 +74,57 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
|
|||
@Test
|
||||
fun `test enter transaction uses constant gas limit Legacy`() = runTest {
|
||||
val fee = TransactionFee.Single(ethLegacyFee())
|
||||
val deployTx = getDeployTx()
|
||||
val enterTx = getEnterTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(emptyList()).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returns fee
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(
|
||||
getDeployTx(),
|
||||
getEnterTx(),
|
||||
),
|
||||
transactionDataList = listOf(deployTx, enterTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
feeRepository.calculateFee(any(), any(), deployTx)
|
||||
}
|
||||
coVerify(inverse = true) {
|
||||
feeRepository.calculateFee(any(), any(), enterTx)
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val deployFee = txs.first().fee as Fee.Ethereum.Legacy
|
||||
val enterFee = txs.last().fee as Fee.Ethereum.Legacy
|
||||
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(21_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(350_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(500_000))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test not enter transaction uses gas limit Legacy`() = runTest {
|
||||
val fee = TransactionFee.Single(ethLegacyFee())
|
||||
val deployTx = getDeployTx()
|
||||
val approveTx = getApproveTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(emptyList()).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returnsMany listOf(fee, fee)
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(
|
||||
getDeployTx(),
|
||||
getApproveTx(),
|
||||
),
|
||||
transactionDataList = listOf(deployTx, approveTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
feeRepository.calculateFee(any(), any(), deployTx)
|
||||
feeRepository.calculateFee(any(), any(), approveTx)
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val deployFee = txs.first().fee as Fee.Ethereum.Legacy
|
||||
val approveFee = txs.last().fee as Fee.Ethereum.Legacy
|
||||
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(21_000))
|
||||
|
|
@ -120,69 +134,88 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
|
|||
@Test
|
||||
fun `test enter transaction with wrong order uses gas limit Legacy`() = runTest {
|
||||
val fee = TransactionFee.Single(ethLegacyFee())
|
||||
val enterTx = getEnterTx()
|
||||
val deployTx = getDeployTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(emptyList()).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returnsMany listOf(fee, fee)
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(
|
||||
getEnterTx(),
|
||||
getDeployTx(),
|
||||
),
|
||||
transactionDataList = listOf(enterTx, deployTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
feeRepository.calculateFee(any(), any(), deployTx)
|
||||
}
|
||||
coVerify(inverse = true) {
|
||||
feeRepository.calculateFee(any(), any(), enterTx)
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val deployFee = txs.first().fee as Fee.Ethereum.Legacy
|
||||
val enterFee = txs.last().fee as Fee.Ethereum.Legacy
|
||||
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(21_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(350_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(500_000))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test enter transaction uses constant gas limit Eip1559`() = runTest {
|
||||
val fee = TransactionFee.Single(ethEip1559Fee())
|
||||
val deployTx = getDeployTx()
|
||||
val enterTx = getEnterTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(emptyList()).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returns fee
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(
|
||||
getDeployTx(),
|
||||
getEnterTx(),
|
||||
),
|
||||
transactionDataList = listOf(deployTx, enterTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
feeRepository.calculateFee(any(), any(), deployTx)
|
||||
}
|
||||
coVerify(inverse = true) {
|
||||
feeRepository.calculateFee(any(), any(), enterTx)
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val deployFee = txs.first().fee as Fee.Ethereum.EIP1559
|
||||
val enterFee = txs.last().fee as Fee.Ethereum.EIP1559
|
||||
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(21_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(350_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(500_000))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test not enter transaction uses gas limit Eip1559`() = runTest {
|
||||
val fee = TransactionFee.Single(ethEip1559Fee())
|
||||
val deployTx = getDeployTx()
|
||||
val approveTx = getApproveTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(emptyList()).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returnsMany listOf(fee, fee)
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(
|
||||
getDeployTx(),
|
||||
getApproveTx(),
|
||||
),
|
||||
transactionDataList = listOf(deployTx, approveTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
feeRepository.calculateFee(any(), any(), deployTx)
|
||||
feeRepository.calculateFee(any(), any(), approveTx)
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val deployFee = txs.first().fee as Fee.Ethereum.EIP1559
|
||||
val approveFee = txs.last().fee as Fee.Ethereum.EIP1559
|
||||
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(21_000))
|
||||
|
|
@ -192,25 +225,137 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
|
|||
@Test
|
||||
fun `test enter transaction with wrong order uses gas limit Eip1559`() = runTest {
|
||||
val fee = TransactionFee.Single(ethEip1559Fee())
|
||||
val enterTx = getEnterTx()
|
||||
val deployTx = getDeployTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(emptyList()).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returnsMany listOf(fee, fee)
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(
|
||||
getEnterTx(),
|
||||
getDeployTx(),
|
||||
),
|
||||
transactionDataList = listOf(enterTx, deployTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
feeRepository.calculateFee(any(), any(), deployTx)
|
||||
}
|
||||
coVerify(inverse = true) {
|
||||
feeRepository.calculateFee(any(), any(), enterTx)
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val deployFee = txs.first().fee as Fee.Ethereum.EIP1559
|
||||
val enterFee = txs.last().fee as Fee.Ethereum.EIP1559
|
||||
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(21_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(350_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(500_000))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test single transaction with fee Legacy`() = runTest {
|
||||
val fee = TransactionFee.Single(ethLegacyFee())
|
||||
val enterTx = getEnterTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(emptyList()).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returns fee
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(enterTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
feeRepository.calculateFee(any(), any(), enterTx)
|
||||
}
|
||||
coVerify(inverse = true) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val enterFee = txs.first().fee as Fee.Ethereum.Legacy
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(21_000))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test enter transaction uses block aid Eip1559`() = runTest {
|
||||
val fee = ethEip1559Fee()
|
||||
val deployTx = getDeployTx()
|
||||
val approveTx = getApproveTx()
|
||||
val enterTx = getEnterTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(
|
||||
estimatedGasList = listOf(1_000.toBigInteger(), 2_000.toBigInteger(), 3_000.toBigInteger()),
|
||||
).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returns mockk()
|
||||
coEvery { feeRepository.getEthereumFeeWithoutGas(any(), any()) } returns fee
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(deployTx, approveTx, enterTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
feeRepository.getEthereumFeeWithoutGas(any(), any())
|
||||
}
|
||||
coVerify(inverse = true) {
|
||||
feeRepository.calculateFee(any(), any(), deployTx)
|
||||
feeRepository.calculateFee(any(), any(), approveTx)
|
||||
feeRepository.calculateFee(any(), any(), enterTx)
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val deployFee = txs.first().fee as Fee.Ethereum.EIP1559
|
||||
val approveFee = txs[1].fee as Fee.Ethereum.EIP1559
|
||||
val enterFee = txs.last().fee as Fee.Ethereum.EIP1559
|
||||
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_000))
|
||||
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_000))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test enter transaction uses block aid Legacy`() = runTest {
|
||||
val fee = ethLegacyFee()
|
||||
val deployTx = getDeployTx()
|
||||
val approveTx = getApproveTx()
|
||||
val enterTx = getEnterTx()
|
||||
|
||||
coEvery { blockAidGasEstimate.getGasEstimation(any(), any()) } returns GasEstimationResult(
|
||||
estimatedGasList = listOf(1_000.toBigInteger(), 2_000.toBigInteger(), 3_000.toBigInteger()),
|
||||
).right()
|
||||
coEvery { feeRepository.calculateFee(any(), any(), any()) } returns mockk()
|
||||
coEvery { feeRepository.getEthereumFeeWithoutGas(any(), any()) } returns fee
|
||||
|
||||
val result = useCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = listOf(deployTx, approveTx, enterTx),
|
||||
)
|
||||
Truth.assertThat(result.isRight()).isTrue()
|
||||
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
blockAidGasEstimate.getGasEstimation(any(), any())
|
||||
feeRepository.getEthereumFeeWithoutGas(any(), any())
|
||||
}
|
||||
coVerify(inverse = true) {
|
||||
feeRepository.calculateFee(any(), any(), deployTx)
|
||||
feeRepository.calculateFee(any(), any(), approveTx)
|
||||
feeRepository.calculateFee(any(), any(), enterTx)
|
||||
}
|
||||
|
||||
val txs = (result as Either.Right).value
|
||||
val deployFee = txs.first().fee as Fee.Ethereum.Legacy
|
||||
val approveFee = txs[1].fee as Fee.Ethereum.Legacy
|
||||
val enterFee = txs.last().fee as Fee.Ethereum.Legacy
|
||||
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_000))
|
||||
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_000))
|
||||
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_000))
|
||||
}
|
||||
|
||||
private fun getDeployTx() = uncompiled(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue