Updated on 2026-08-14
This commit is contained in:
parent
90c43018fd
commit
471343e66b
5 changed files with 269 additions and 133 deletions
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.domain.transaction
|
||||
|
||||
import arrow.core.raise.Raise
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
|
||||
fun Raise<GetFeeError>.raiseIllegalStateError(error: String): Nothing {
|
||||
raise(GetFeeError.DataError(IllegalStateException(error)))
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
|
|||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.transaction.GaslessTransactionRepository
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.raiseIllegalStateError
|
||||
import java.math.BigDecimal
|
||||
|
||||
class GetAvailableFeeTokensUseCase(
|
||||
|
|
@ -82,8 +83,4 @@ class GetAvailableFeeTokensUseCase(
|
|||
}
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun Raise<GetFeeError>.raiseIllegalStateError(error: String): Nothing {
|
||||
raise(GetFeeError.DataError(IllegalStateException(error)))
|
||||
}
|
||||
}
|
||||
|
|
@ -5,14 +5,9 @@ import arrow.core.raise.Raise
|
|||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||
import com.tangem.blockchain.blockchains.ethereum.tokenmethods.TransferERC20TokenCallData
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Token
|
||||
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.domain.demo.DemoTransactionSender
|
||||
import com.tangem.domain.demo.models.DemoConfig
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
|
|
@ -23,12 +18,11 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|||
import com.tangem.domain.transaction.GaslessTransactionRepository
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.error.GetFeeError.GaslessError
|
||||
import com.tangem.domain.transaction.error.mapToFeeError
|
||||
import com.tangem.domain.transaction.models.TransactionFeeExtended
|
||||
import com.tangem.domain.transaction.raiseIllegalStateError
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
class GetFeeForGaslessUseCase(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
|
|
@ -39,6 +33,12 @@ class GetFeeForGaslessUseCase(
|
|||
private val getFeeUseCase: GetFeeUseCase,
|
||||
) {
|
||||
|
||||
private val tokenFeeCalculator = TokenFeeCalculator(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
gaslessTransactionRepository = gaslessTransactionRepository,
|
||||
demoConfig = demoConfig,
|
||||
)
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWallet: UserWallet,
|
||||
network: Network,
|
||||
|
|
@ -67,12 +67,12 @@ class GetFeeForGaslessUseCase(
|
|||
|
||||
val walletManager = prepareWalletManager(userWallet, network)
|
||||
|
||||
val initialFee = calculateInitialFee(
|
||||
val initialFee = tokenFeeCalculator.calculateInitialFee(
|
||||
userWallet = userWallet,
|
||||
network = network,
|
||||
walletManager = walletManager,
|
||||
transactionData = transactionData,
|
||||
)
|
||||
).bind()
|
||||
|
||||
selectFeePaymentStrategy(
|
||||
userWallet = userWallet,
|
||||
|
|
@ -103,27 +103,6 @@ class GetFeeForGaslessUseCase(
|
|||
return ethereumWalletManager
|
||||
}
|
||||
|
||||
private suspend fun Raise<GetFeeError>.calculateInitialFee(
|
||||
userWallet: UserWallet,
|
||||
network: Network,
|
||||
walletManager: EthereumWalletManager,
|
||||
transactionData: TransactionData,
|
||||
): TransactionFee {
|
||||
val transactionSender = if (userWallet is UserWallet.Cold &&
|
||||
demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)
|
||||
) {
|
||||
demoTransactionSender(userWallet, network)
|
||||
} else {
|
||||
walletManager
|
||||
}
|
||||
|
||||
val maybeFee = when (val result = transactionSender.getFee(transactionData = transactionData)) {
|
||||
is Result.Success -> result.data
|
||||
is Result.Failure -> raise(result.mapToFeeError())
|
||||
}
|
||||
return maybeFee
|
||||
}
|
||||
|
||||
private suspend fun Raise<GetFeeError>.selectFeePaymentStrategy(
|
||||
userWallet: UserWallet,
|
||||
walletManager: EthereumWalletManager,
|
||||
|
|
@ -183,104 +162,12 @@ class GetFeeForGaslessUseCase(
|
|||
val tokenForPayFeeStatus = supportedGaslessTokensStatusesSortedByBalanceDesc.firstOrNull()
|
||||
?: raise(GaslessError.NoSupportedTokensFound)
|
||||
|
||||
return calculateTokenFee(
|
||||
return tokenFeeCalculator.calculateTokenFee(
|
||||
walletManager = walletManager,
|
||||
tokenForPayFeeStatus = tokenForPayFeeStatus,
|
||||
nativeCurrencyStatus = nativeCurrencyStatus,
|
||||
initialFee = initialFee,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun Raise<GetFeeError>.calculateTokenFee(
|
||||
walletManager: EthereumWalletManager,
|
||||
tokenForPayFeeStatus: CryptoCurrencyStatus,
|
||||
nativeCurrencyStatus: CryptoCurrencyStatus,
|
||||
initialFee: Fee.Ethereum,
|
||||
): TransactionFeeExtended {
|
||||
val tokenForPayFee = tokenForPayFeeStatus.currency as? CryptoCurrency.Token
|
||||
?: raiseIllegalStateError("only tokens are supported")
|
||||
|
||||
val transferFeeToContractAmount = createTokenAmount(tokenForPayFee, BigDecimal(FEE_TRANSFER_AMOUNT))
|
||||
val feeDestination = gaslessTransactionRepository.getTokenFeeReceiverAddress()
|
||||
val feeTransferGasLimitResult = walletManager.getGasLimit(
|
||||
amount = transferFeeToContractAmount,
|
||||
destination = feeDestination,
|
||||
callData = TransferERC20TokenCallData(
|
||||
destination = feeDestination,
|
||||
amount = transferFeeToContractAmount,
|
||||
),
|
||||
)
|
||||
|
||||
val feeTransferGasLimit = when (feeTransferGasLimitResult) {
|
||||
is Result.Failure -> raise(GetFeeError.DataError(feeTransferGasLimitResult.error))
|
||||
is Result.Success -> feeTransferGasLimitResult.data
|
||||
}
|
||||
|
||||
val baseGas = gaslessTransactionRepository.getBaseGasForTransaction()
|
||||
|
||||
val maxTokenFeeGas = initialFee.gasLimit + feeTransferGasLimit + baseGas
|
||||
|
||||
val maxFeePerGas = when (initialFee) {
|
||||
is Fee.Ethereum.EIP1559 -> initialFee.maxFeePerGas
|
||||
is Fee.Ethereum.Legacy -> initialFee.gasPrice
|
||||
is Fee.Ethereum.TokenCurrency -> raiseIllegalStateError("initialFee could only be native")
|
||||
}
|
||||
|
||||
val feeInNativeCurrency = maxTokenFeeGas
|
||||
.multiply(maxFeePerGas)
|
||||
.multiply(GAS_PRICE_MULTIPLIER.toBigInteger())
|
||||
|
||||
val nativeFiatRate = nativeCurrencyStatus.value.fiatRate ?: raiseIllegalStateError("fiatRate is null")
|
||||
val tokenFiatRate = tokenForPayFeeStatus.value.fiatRate ?: raiseIllegalStateError("fiatRate is null")
|
||||
val coinPriceInToken = nativeFiatRate.divide(
|
||||
tokenFiatRate,
|
||||
maxOf(nativeCurrencyStatus.currency.decimals, tokenForPayFee.decimals),
|
||||
RoundingMode.DOWN,
|
||||
)
|
||||
|
||||
val feeInTokenCurrency = coinPriceInToken.multiply(feeInNativeCurrency.toBigDecimal())
|
||||
|
||||
val tokenBalance = tokenForPayFeeStatus.value.amount ?: BigDecimal.ZERO
|
||||
if (tokenBalance < feeInTokenCurrency) {
|
||||
raise(GaslessError.NotEnoughFunds)
|
||||
}
|
||||
|
||||
val amount = createTokenAmount(tokenForPayFee, feeInTokenCurrency)
|
||||
|
||||
val fee = Fee.Ethereum.TokenCurrency(
|
||||
amount = amount,
|
||||
gasLimit = maxTokenFeeGas,
|
||||
coinPriceInToken = coinPriceInToken,
|
||||
feeTransferGasLimit = feeTransferGasLimit,
|
||||
baseGas = baseGas,
|
||||
)
|
||||
return TransactionFeeExtended(
|
||||
transactionFee = TransactionFee.Single(normal = fee),
|
||||
feeTokenId = tokenForPayFee.id,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createTokenAmount(token: CryptoCurrency.Token, value: BigDecimal): Amount = Amount(
|
||||
token = Token(
|
||||
symbol = token.symbol,
|
||||
contractAddress = token.contractAddress,
|
||||
decimals = token.decimals,
|
||||
),
|
||||
value = value,
|
||||
)
|
||||
|
||||
private suspend fun Raise<GetFeeError>.demoTransactionSender(
|
||||
userWallet: UserWallet,
|
||||
network: Network,
|
||||
): DemoTransactionSender {
|
||||
return DemoTransactionSender(
|
||||
walletManagersFacade.getOrCreateWalletManager(userWallet.walletId, network)
|
||||
?: raiseIllegalStateError("WalletManager is null"),
|
||||
)
|
||||
}
|
||||
|
||||
private fun Raise<GetFeeError>.raiseIllegalStateError(error: String): Nothing {
|
||||
raise(GetFeeError.DataError(IllegalStateException(error)))
|
||||
).bind()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,101 @@
|
|||
package com.tangem.domain.transaction.usecase.gasless
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.demo.models.DemoConfig
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.transaction.GaslessTransactionRepository
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.models.TransactionFeeExtended
|
||||
import com.tangem.domain.transaction.raiseIllegalStateError
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
|
||||
class GetFeeForTokenUseCase {
|
||||
class GetFeeForTokenUseCase(
|
||||
private val gaslessTransactionRepository: GaslessTransactionRepository,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val demoConfig: DemoConfig,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
|
||||
) {
|
||||
|
||||
operator fun invoke(token: CryptoCurrency, transactionData: TransactionData): Either<GetFeeError, TransactionFee> {
|
||||
return GetFeeError.UnknownError.left()
|
||||
private val tokenFeeCalculator = TokenFeeCalculator(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
gaslessTransactionRepository = gaslessTransactionRepository,
|
||||
demoConfig = demoConfig,
|
||||
)
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWallet: UserWallet,
|
||||
token: CryptoCurrency,
|
||||
transactionData: TransactionData,
|
||||
): Either<GetFeeError, TransactionFeeExtended> {
|
||||
return either {
|
||||
if (!gaslessTransactionRepository.isNetworkSupported(token.network)) {
|
||||
raise(GetFeeError.GaslessError.NetworkIsNotSupported)
|
||||
}
|
||||
|
||||
val walletManager = prepareWalletManager(userWallet, token.network)
|
||||
|
||||
val initialTxFee = tokenFeeCalculator.calculateInitialFee(
|
||||
userWallet = userWallet,
|
||||
network = token.network,
|
||||
walletManager = walletManager,
|
||||
transactionData = transactionData,
|
||||
).bind()
|
||||
|
||||
val initialFeeEth = initialTxFee.normal as? Fee.Ethereum
|
||||
?: raiseIllegalStateError(
|
||||
error = "only Fee.Ethereum supported, but was different",
|
||||
)
|
||||
|
||||
val nativeCurrency = currenciesRepository.getNetworkCoin(
|
||||
userWalletId = userWallet.walletId,
|
||||
networkId = token.network.id,
|
||||
derivationPath = token.network.derivationPath,
|
||||
)
|
||||
|
||||
val userCurrenciesStatusesByNetwork = getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
|
||||
userWallet.walletId,
|
||||
).getOrNull()?.filter {
|
||||
it.currency.network.id == token.network.id
|
||||
} ?: raiseIllegalStateError("currencies list is null for userWalletId=${userWallet.walletId}")
|
||||
|
||||
val nativeCurrencyStatus = userCurrenciesStatusesByNetwork.find {
|
||||
it.currency.id == nativeCurrency.id
|
||||
} ?: raiseIllegalStateError("native currency not found for network ${token.network.id}")
|
||||
|
||||
val tokenCurrencyStatus = userCurrenciesStatusesByNetwork.find {
|
||||
it.currency.id == token.id
|
||||
} ?: raiseIllegalStateError("token currency not found for network ${token.network.id}")
|
||||
|
||||
tokenFeeCalculator.calculateTokenFee(
|
||||
walletManager = walletManager,
|
||||
tokenForPayFeeStatus = tokenCurrencyStatus,
|
||||
nativeCurrencyStatus = nativeCurrencyStatus,
|
||||
initialFee = initialFeeEth,
|
||||
).bind()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("NullableToStringCall")
|
||||
private suspend fun Raise<GetFeeError>.prepareWalletManager(
|
||||
userWallet: UserWallet,
|
||||
network: Network,
|
||||
): EthereumWalletManager {
|
||||
val walletManager = walletManagersFacade.getOrCreateWalletManager(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = network,
|
||||
)
|
||||
val ethereumWalletManager = walletManager as? EthereumWalletManager
|
||||
?: raiseIllegalStateError("WalletManager type ${walletManager?.javaClass?.name} not supported")
|
||||
return ethereumWalletManager
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
package com.tangem.domain.transaction.usecase.gasless
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||
import com.tangem.blockchain.blockchains.ethereum.tokenmethods.TransferERC20TokenCallData
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Token
|
||||
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.domain.demo.DemoTransactionSender
|
||||
import com.tangem.domain.demo.models.DemoConfig
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.transaction.GaslessTransactionRepository
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.error.GetFeeError.GaslessError
|
||||
import com.tangem.domain.transaction.error.mapToFeeError
|
||||
import com.tangem.domain.transaction.models.TransactionFeeExtended
|
||||
import com.tangem.domain.transaction.raiseIllegalStateError
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
internal class TokenFeeCalculator(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val gaslessTransactionRepository: GaslessTransactionRepository,
|
||||
private val demoConfig: DemoConfig,
|
||||
) {
|
||||
|
||||
suspend fun calculateInitialFee(
|
||||
userWallet: UserWallet,
|
||||
network: Network,
|
||||
walletManager: EthereumWalletManager,
|
||||
transactionData: TransactionData,
|
||||
): Either<GetFeeError, TransactionFee> {
|
||||
return either {
|
||||
val transactionSender = if (userWallet is UserWallet.Cold &&
|
||||
demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)
|
||||
) {
|
||||
demoTransactionSender(userWallet, network)
|
||||
} else {
|
||||
walletManager
|
||||
}
|
||||
|
||||
val maybeFee = when (val result = transactionSender.getFee(transactionData = transactionData)) {
|
||||
is Result.Success -> result.data
|
||||
is Result.Failure -> raise(result.mapToFeeError())
|
||||
}
|
||||
maybeFee
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun calculateTokenFee(
|
||||
walletManager: EthereumWalletManager,
|
||||
tokenForPayFeeStatus: CryptoCurrencyStatus,
|
||||
nativeCurrencyStatus: CryptoCurrencyStatus,
|
||||
initialFee: Fee.Ethereum,
|
||||
): Either<GetFeeError, TransactionFeeExtended> {
|
||||
return either {
|
||||
val tokenForPayFee = tokenForPayFeeStatus.currency as? CryptoCurrency.Token
|
||||
?: raiseIllegalStateError("only tokens are supported")
|
||||
|
||||
val transferFeeToContractAmount = createTokenAmount(
|
||||
token = tokenForPayFee,
|
||||
value = BigDecimal(FEE_TRANSFER_AMOUNT),
|
||||
)
|
||||
val feeDestination = gaslessTransactionRepository.getTokenFeeReceiverAddress()
|
||||
val feeTransferGasLimitResult = walletManager.getGasLimit(
|
||||
amount = transferFeeToContractAmount,
|
||||
destination = feeDestination,
|
||||
callData = TransferERC20TokenCallData(
|
||||
destination = feeDestination,
|
||||
amount = transferFeeToContractAmount,
|
||||
),
|
||||
)
|
||||
|
||||
val feeTransferGasLimit = when (feeTransferGasLimitResult) {
|
||||
is Result.Failure -> raise(GetFeeError.DataError(feeTransferGasLimitResult.error))
|
||||
is Result.Success -> feeTransferGasLimitResult.data
|
||||
}
|
||||
|
||||
val baseGas = gaslessTransactionRepository.getBaseGasForTransaction()
|
||||
|
||||
val maxTokenFeeGas = initialFee.gasLimit + feeTransferGasLimit + baseGas
|
||||
|
||||
val maxFeePerGas = when (initialFee) {
|
||||
is Fee.Ethereum.EIP1559 -> initialFee.maxFeePerGas
|
||||
is Fee.Ethereum.Legacy -> initialFee.gasPrice
|
||||
is Fee.Ethereum.TokenCurrency -> raiseIllegalStateError("initialFee could only be native")
|
||||
}
|
||||
|
||||
val feeInNativeCurrency = maxTokenFeeGas
|
||||
.multiply(maxFeePerGas)
|
||||
.multiply(GAS_PRICE_MULTIPLIER.toBigInteger())
|
||||
|
||||
val nativeFiatRate = nativeCurrencyStatus.value.fiatRate ?: raiseIllegalStateError("fiatRate is null")
|
||||
val tokenFiatRate = tokenForPayFeeStatus.value.fiatRate ?: raiseIllegalStateError("fiatRate is null")
|
||||
val coinPriceInToken = nativeFiatRate.divide(
|
||||
tokenFiatRate,
|
||||
maxOf(nativeCurrencyStatus.currency.decimals, tokenForPayFee.decimals),
|
||||
RoundingMode.DOWN,
|
||||
)
|
||||
|
||||
val feeInTokenCurrency = coinPriceInToken.multiply(feeInNativeCurrency.toBigDecimal())
|
||||
|
||||
val tokenBalance = tokenForPayFeeStatus.value.amount ?: BigDecimal.ZERO
|
||||
if (tokenBalance < feeInTokenCurrency) {
|
||||
raise(GaslessError.NotEnoughFunds)
|
||||
}
|
||||
|
||||
val amount = createTokenAmount(tokenForPayFee, feeInTokenCurrency)
|
||||
|
||||
val fee = Fee.Ethereum.TokenCurrency(
|
||||
amount = amount,
|
||||
gasLimit = maxTokenFeeGas,
|
||||
coinPriceInToken = coinPriceInToken,
|
||||
feeTransferGasLimit = feeTransferGasLimit,
|
||||
baseGas = baseGas,
|
||||
)
|
||||
TransactionFeeExtended(
|
||||
transactionFee = TransactionFee.Single(normal = fee),
|
||||
feeTokenId = tokenForPayFee.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTokenAmount(token: CryptoCurrency.Token, value: BigDecimal): Amount = Amount(
|
||||
token = Token(
|
||||
symbol = token.symbol,
|
||||
contractAddress = token.contractAddress,
|
||||
decimals = token.decimals,
|
||||
),
|
||||
value = value,
|
||||
)
|
||||
|
||||
private suspend fun Raise<GetFeeError>.demoTransactionSender(
|
||||
userWallet: UserWallet,
|
||||
network: Network,
|
||||
): DemoTransactionSender {
|
||||
return DemoTransactionSender(
|
||||
walletManagersFacade.getOrCreateWalletManager(userWallet.walletId, network)
|
||||
?: raiseIllegalStateError("WalletManager is null"),
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
/** Amount in token units for fee transfer */
|
||||
const val FEE_TRANSFER_AMOUNT = 10000
|
||||
/** Gas price safety multiplier for fee calculation */
|
||||
const val GAS_PRICE_MULTIPLIER = 2
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue