diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/cardano/CardanoTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/cardano/CardanoTransactionBuilder.kt index fded86074..1efcf33c7 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/cardano/CardanoTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/cardano/CardanoTransactionBuilder.kt @@ -194,7 +194,7 @@ internal class CardanoTransactionBuilder( is AmountType.Token -> { val minAdaValue = twTxBuilder.calculateMinAdaValueToWithdrawToken( contractAddress = type.token.contractAddress, - amount = transactionData.amount.longValueOrZero, + amount = transactionData.amount.longValue, ) plan.amount < minAdaValue @@ -238,7 +238,7 @@ internal class CardanoTransactionBuilder( ) val remainingAmount = if (isTransactionToken == true) { - amount - transactionData.amount.longValueOrZero + amount - transactionData.amount.longValue } else { amount } diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/cardano/walletcore/CardanoTWTxBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/cardano/walletcore/CardanoTWTxBuilder.kt index 913453b98..2b704e046 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/cardano/walletcore/CardanoTWTxBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/cardano/walletcore/CardanoTWTxBuilder.kt @@ -78,13 +78,13 @@ internal class CardanoTWTxBuilder( when (val type = transactionData.amount.type) { is AmountType.Coin -> { - this.amount = transactionData.amount.longValueOrZero + this.amount = transactionData.amount.longValue } is AmountType.Token -> { setTokenAmount( contractAddress = type.token.contractAddress, - amount = transactionData.amount.longValueOrZero, - fee = transactionData.fee?.amount?.longValueOrZero ?: 0, + amount = transactionData.amount.longValue, + fee = transactionData.fee?.amount?.longValue ?: 0L, ) } else -> throw BlockchainSdkError.CustomError("AmountType $type is not supported") @@ -101,7 +101,7 @@ internal class CardanoTWTxBuilder( val tokenBundle = createTokenBundle(contractAddress = contractAddress, amount = amount) val minAdaValue = minAdaAmount(tokenBundle.toByteArray()) - val balance = wallet.getCoinAmount().longValueOrZero + val balance = wallet.getCoinAmount().longValue val remainingBalance = balance - minAdaValue - fee diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/casper/CasperTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/casper/CasperTransactionBuilder.kt index 733b9a582..3ee643b3e 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/casper/CasperTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/casper/CasperTransactionBuilder.kt @@ -36,8 +36,8 @@ internal class CasperTransactionBuilder(private val wallet: Wallet) { private fun buildTransaction(transactionData: TransactionData): CasperTransactionBody { transactionData.requireUncompiled() - val amount = transactionData.amount.longValueOrZero.toBigInteger() - val fee = (transactionData.fee as Fee.Common).amount.longValueOrZero.toBigInteger() + val amount = transactionData.amount.longValue.toBigInteger() + val fee = (transactionData.fee as Fee.Common).amount.longValue.toBigInteger() val id = (transactionData.extras as? CasperTransactionExtras)?.memo val session = CasperTransactionBody.Session( diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/kaspa/KaspaTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/kaspa/KaspaTransactionBuilder.kt index 46ac25838..b15b4ac41 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/kaspa/KaspaTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/kaspa/KaspaTransactionBuilder.kt @@ -5,7 +5,10 @@ import com.tangem.blockchain.blockchains.kaspa.kaspacashaddr.KaspaAddressType import com.tangem.blockchain.blockchains.kaspa.kaspacashaddr.KaspaCashAddr import com.tangem.blockchain.blockchains.kaspa.krc20.model.* import com.tangem.blockchain.blockchains.kaspa.network.* -import com.tangem.blockchain.common.* +import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.BlockchainSdkError +import com.tangem.blockchain.common.TransactionData +import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.common.transaction.Fee import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.network.moshi @@ -168,7 +171,7 @@ class KaspaTransactionBuilder( val envelope = Envelope( p = "krc-20", op = "transfer", - amt = transactionData.amount.longValueOrZero.toString(), + amt = transactionData.amount.longValue.toString(), to = transactionData.destinationAddress, tick = transactionData.amount.type.token.contractAddress, ) diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ton/TonTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ton/TonTransactionBuilder.kt index 5f7ca7766..742c1eec1 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ton/TonTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ton/TonTransactionBuilder.kt @@ -2,11 +2,11 @@ package com.tangem.blockchain.blockchains.ton import com.google.protobuf.ByteString import com.tangem.blockchain.common.* +import com.tangem.blockchain.extensions.Result import com.tangem.common.KeyPair import com.tangem.common.card.EllipticCurve import com.tangem.crypto.CryptoUtils import wallet.core.jni.proto.TheOpenNetwork -import com.tangem.blockchain.extensions.Result internal class TonTransactionBuilder(private val walletAddress: String) { @@ -73,7 +73,7 @@ internal class TonTransactionBuilder(private val walletAddress: String) { val jettonTransfer = TheOpenNetwork.JettonTransfer.newBuilder() .setTransfer(transfer) - .setJettonAmount(amount.longValueOrZero) + .setJettonAmount(amount.longValue) .setToOwner(destination) .setResponseAddress(walletAddress) .setForwardAmount(1) // some amount needed to send "jetton transfer notification", use minimum @@ -98,7 +98,7 @@ internal class TonTransactionBuilder(private val walletAddress: String) { return TheOpenNetwork.Transfer.newBuilder() .setWalletVersion(TheOpenNetwork.WalletVersion.WALLET_V4_R2) .setDest(destination) - .setAmount(amount.longValueOrZero) + .setAmount(amount.longValue) .setSequenceNumber(sequenceNumber) .setMode(modeTransactionConstant) .setBounceable(bounceable) diff --git a/blockchain/src/main/java/com/tangem/blockchain/common/Amount.kt b/blockchain/src/main/java/com/tangem/blockchain/common/Amount.kt index 0a8f370d5..66644cba4 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/common/Amount.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/common/Amount.kt @@ -11,11 +11,9 @@ data class Amount( val type: AmountType = AmountType.Coin, ) { - // Be careful! The property may overflow if the decimals are much larger than the long value. - val longValue get() = value?.movePointRight(decimals)?.toLong() - - // Be careful! The property may overflow if the decimals are much larger than the long value. - val longValueOrZero: Long by lazy { value?.movePointRight(decimals)?.toLong() ?: 0L } + val longValue get() = requireNotNull(value = value, lazyMessage = { "Amount value is null" }) + .movePointRight(decimals) + .longValueExact() constructor( value: BigDecimal?, diff --git a/blockchain/src/test/java/com/tangem/blockchain/common/AmountTests.kt b/blockchain/src/test/java/com/tangem/blockchain/common/AmountTests.kt new file mode 100644 index 000000000..5341c705f --- /dev/null +++ b/blockchain/src/test/java/com/tangem/blockchain/common/AmountTests.kt @@ -0,0 +1,57 @@ +package com.tangem.blockchain.common + +import com.google.common.truth.Truth +import org.junit.Test +import java.math.BigDecimal +import kotlin.math.pow + +/** + * @author Andrew Khokhlov on 16/12/2024 + */ +internal class AmountTests { + + @Test + fun null_amount() { + val amount = Amount(blockchain = Blockchain.Bitcoin).copy(value = null) + + try { + amount.longValue + + error("Should be exception") + } catch (e: Exception) { + Truth.assertThat(e).isInstanceOf(IllegalArgumentException::class.java) + Truth.assertThat(e).hasMessageThat().isEqualTo("Amount value is null") + } + } + + @Test + fun zero_amount() { + val amount = Amount(blockchain = Blockchain.Bitcoin).copy(value = BigDecimal.ZERO) + + Truth.assertThat(amount.longValue).isEqualTo(0L) + } + + @Test + fun simple_amount() { + val value = 1000L + val amount = Amount(blockchain = Blockchain.Bitcoin).copy(value = BigDecimal(value)) + + val expected = value * 10f.pow(Blockchain.Bitcoin.decimals()).toLong() + + Truth.assertThat(amount.longValue).isEqualTo(expected) + } + + @Test + fun long_max_value_amount() { + val amount = Amount(blockchain = Blockchain.Bitcoin).copy(value = Long.MAX_VALUE.toBigDecimal()) + + try { + amount.longValue + + error("Should be exception") + } catch (e: Exception) { + Truth.assertThat(e).isInstanceOf(ArithmeticException::class.java) + Truth.assertThat(e).hasMessageThat().isEqualTo("Overflow") + } + } +}