Skip to content

Commit

Permalink
AND-8877 Fix bugs and review issues
Browse files Browse the repository at this point in the history
  • Loading branch information
nzeeei committed Dec 6, 2024
1 parent c1d556c commit 6805bf4
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ internal class HederaWalletManager(
}
}

override suspend fun discardRequirements(currencyType: CryptoCurrencyType): SimpleResult {
return SimpleResult.Success
}

override suspend fun send(
transactionData: TransactionData,
signer: TransactionSigner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import java.math.BigInteger
class KaspaTransactionBuilder(
private val publicKey: Wallet.PublicKey,
) {
private lateinit var transaction: KaspaTransaction
private var networkParameters = KaspaMainNetParams()
var unspentOutputs: List<KaspaUnspentOutput>? = null

Expand All @@ -34,7 +33,7 @@ class KaspaTransactionBuilder(
private val envelopeAdapter by lazy { moshi.adapter<Envelope>() }

@Suppress("MagicNumber")
fun buildToSign(transactionData: TransactionData): Result<List<ByteArray>> {
fun buildToSign(transactionData: TransactionData): Result<KaspaTransaction> {
transactionData.requireUncompiled()

if (unspentOutputs.isNullOrEmpty()) {
Expand Down Expand Up @@ -74,7 +73,7 @@ class KaspaTransactionBuilder(
null -> error("Null script type") // should never happen
}

transaction = createKaspaTransaction(
val transaction = createKaspaTransaction(
networkParameters = networkParameters,
unspentOutputs = unspentsToSpend,
transformer = { kaspaTransaction ->
Expand All @@ -92,18 +91,18 @@ class KaspaTransactionBuilder(
},
)

return Result.Success(getHashesForSign(transaction))
return Result.Success(transaction)
}

fun buildToSend(signatures: ByteArray, transaction: KaspaTransaction = this.transaction): KaspaTransactionBody {
fun buildToSend(signatures: ByteArray, transaction: KaspaTransaction): KaspaTransactionBody {
for (index in transaction.inputs.indices) {
val signature = extractSignature(index, signatures)
transaction.inputs[index].scriptSig = ScriptBuilder().data(signature).build()
}
return buildForSendInternal(transaction)
}

fun buildKRC20RevealToSend(
internal fun buildKRC20RevealToSend(
signatures: ByteArray,
redeemScript: RedeemScript,
transaction: KaspaTransaction,
Expand All @@ -123,15 +122,21 @@ class KaspaTransactionBuilder(
}

@Suppress("LongMethod", "MagicNumber")
fun buildKRC20CommitTransactionToSign(
internal fun buildKRC20CommitTransactionToSign(
transactionData: TransactionData,
dust: BigDecimal,
dust: BigDecimal?,
includeFee: Boolean = true,
): Result<CommitTransaction> {
transactionData.requireUncompiled()

require(transactionData.amount.type is AmountType.Token)

if (unspentOutputs.isNullOrEmpty()) {
return Result.Failure(
BlockchainSdkError.CustomError("Unspent outputs are missing"),
)
}

val unspentsToSpend = getUnspentsToSpend()

val transactionFeeAmountValue = transactionData.fee?.amount?.value ?: BigDecimal.ZERO
Expand All @@ -151,7 +156,7 @@ class KaspaTransactionBuilder(
val revealFeeParams = (transactionData.fee as? Fee.Kaspa)?.revealTransactionFee?.takeIf { includeFee }
// if we don't know the commission, commission for reveal transaction will be set to zero
val feeEstimationRevealTransactionValue = revealFeeParams?.value ?: BigDecimal.ZERO
val targetOutputAmountValue = feeEstimationRevealTransactionValue + dust
val targetOutputAmountValue = feeEstimationRevealTransactionValue + (dust ?: BigDecimal.ZERO)

val resultChange = calculateChange(
amount = targetOutputAmountValue,
Expand All @@ -173,7 +178,7 @@ class KaspaTransactionBuilder(
envelope = envelope,
)

transaction = createKaspaTransaction(
val transaction = createKaspaTransaction(
networkParameters = networkParameters,
unspentOutputs = unspentsToSpend,
transformer = { kaspaTransaction ->
Expand All @@ -197,7 +202,7 @@ class KaspaTransactionBuilder(
)
val commitTransaction = CommitTransaction(
transaction = transaction,
hashes = getHashesForSign(),
hashes = getHashesForSign(transaction),
redeemScript = redeemScript,
sourceAddress = transactionData.sourceAddress,
params = IncompleteTokenTransactionParams(
Expand Down Expand Up @@ -301,7 +306,7 @@ class KaspaTransactionBuilder(

fun getUnspentsToSpend() = unspentOutputs!!.sortedByDescending { it.amount }.take(getUnspentsToSpendCount())

private fun getHashesForSign(transaction: KaspaTransaction = this.transaction): List<ByteArray> {
fun getHashesForSign(transaction: KaspaTransaction): List<ByteArray> {
val hashesForSign: MutableList<ByteArray> = MutableList(transaction.inputs.size) { byteArrayOf() }
for (input in transaction.inputs) {
val index = input.index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,28 @@ internal class KaspaWalletManager(

val coinBalance = coinBalanceDeferred.await()

if (coinBalance is Result.Success && tokensBalances is Result.Success) {
updateWallet(coinBalance.data, tokensBalances.data)
} else if (coinBalance is Result.Failure) {
updateError(coinBalance.error)
} else if (tokensBalances is Result.Failure) {
updateError(tokensBalances.error)
if (tokensBalances is Result.Success) {
updateWalletTokens(tokensBalances.data)
}

when (coinBalance) {
is Result.Success -> updateWallet(coinBalance.data)
is Result.Failure -> updateError(coinBalance.error)
}
}
}

private fun updateWallet(response: KaspaInfoResponse, tokensInfo: List<KaspaKRC20InfoResponse>) {
private fun updateWallet(response: KaspaInfoResponse) {
Log.d(this::class.java.simpleName, "Balance is ${response.balance}")
if (response.balance != wallet.amounts[AmountType.Coin]?.value) {
// assume outgoing transaction has been finalized if balance has changed
wallet.recentTransactions.clear()
}
wallet.changeAmountValue(AmountType.Coin, response.balance)
transactionBuilder.unspentOutputs = response.unspentOutputs
}

private fun updateWalletTokens(tokensInfo: List<KaspaKRC20InfoResponse>) {
tokensInfo.forEach { result ->
val token = result.token
val balance = result.balance
Expand Down Expand Up @@ -133,7 +136,7 @@ internal class KaspaWalletManager(
).let {
when (it) {
is Result.Failure -> it
is Result.Success -> Result.Success(it.data.hashes)
is Result.Success -> Result.Success(it.data.transaction)
}
}
else -> error("unknown amount type for fee estimation")
Expand All @@ -142,10 +145,13 @@ internal class KaspaWalletManager(
when (buildTransactionResult) {
is Result.Failure -> return buildTransactionResult
is Result.Success -> {
return when (val signerResult = dummySigner.sign(buildTransactionResult.data, wallet.publicKey)) {
val transaction = buildTransactionResult.data
val hashesToSign = transactionBuilder.getHashesForSign(transaction)
return when (val signerResult = dummySigner.sign(hashesToSign, wallet.publicKey)) {
is CompletionResult.Success -> {
val transactionToSend = transactionBuilder.buildToSend(
signerResult.data.reduce { acc, bytes -> acc + bytes },
signatures = signerResult.data.reduce { acc, bytes -> acc + bytes },
transaction = transaction,
)
when (val sendResult = networkProvider.calculateFee(transactionToSend.transaction)) {
is Result.Failure -> sendResult
Expand Down Expand Up @@ -228,7 +234,7 @@ internal class KaspaWalletManager(
transactionData = incompleteTokenTransaction
.toIncompleteTokenTransactionParams()
.toTransactionData(
token = currencyType.info,
type = AmountType.Token(currencyType.info),
),
signer = signer,
)
Expand All @@ -241,13 +247,14 @@ internal class KaspaWalletManager(
}
}

override suspend fun discardRequirements(currencyType: CryptoCurrencyType) {
override suspend fun discardRequirements(currencyType: CryptoCurrencyType): SimpleResult {
when (currencyType) {
is CryptoCurrencyType.Coin -> return
is CryptoCurrencyType.Coin -> Unit
is CryptoCurrencyType.Token -> {
removeIncompleteTokenTransaction(currencyType.info)
}
}
return SimpleResult.Success
}

private suspend fun sendCoinTransaction(
Expand All @@ -257,10 +264,13 @@ internal class KaspaWalletManager(
when (val buildTransactionResult = transactionBuilder.buildToSign(transactionData)) {
is Result.Failure -> return buildTransactionResult
is Result.Success -> {
return when (val signerResult = signer.sign(buildTransactionResult.data, wallet.publicKey)) {
val transaction = buildTransactionResult.data
val hashesToSign = transactionBuilder.getHashesForSign(transaction)
return when (val signerResult = signer.sign(hashesToSign, wallet.publicKey)) {
is CompletionResult.Success -> {
val transactionToSend = transactionBuilder.buildToSend(
signerResult.data.reduce { acc, bytes -> acc + bytes },
signatures = signerResult.data.reduce { acc, bytes -> acc + bytes },
transaction = transaction,
)
when (val sendResult = networkProvider.sendTransaction(transactionToSend)) {
is Result.Failure -> sendResult
Expand Down Expand Up @@ -322,7 +332,7 @@ internal class KaspaWalletManager(
) {
is Result.Failure -> sendCommitResult
is Result.Success -> {
store(
storeIncompleteTokenTransaction(
token = token,
data = commitTransaction.data
.params
Expand All @@ -339,6 +349,7 @@ internal class KaspaWalletManager(
is Result.Success -> {
val hash = sendRevealResult.data
transactionData.hash = hash
wallet.addOutgoingTransaction(transactionData)
removeIncompleteTokenTransaction(token)
Result.Success(TransactionSendResult(hash ?: ""))
}
Expand All @@ -356,7 +367,8 @@ internal class KaspaWalletManager(
}
}

private fun IncompleteTokenTransactionParams.toTransactionData(token: Token): TransactionData.Uncompiled {
private fun IncompleteTokenTransactionParams.toTransactionData(type: AmountType.Token): TransactionData.Uncompiled {
val token = type.token
val tokenValue = BigDecimal(envelope.amt)

val transactionAmount = tokenValue.movePointLeft(token.decimals)
Expand All @@ -370,7 +382,7 @@ internal class KaspaWalletManager(
amount = Amount(
value = transactionAmount,
blockchain = blockchain,
type = AmountType.Token(token),
type = type,
),
fee = Fee.Kaspa(
amount = feeAmount,
Expand Down Expand Up @@ -398,7 +410,7 @@ internal class KaspaWalletManager(
(transactionData.extras as KaspaKRC20TransactionExtras).incompleteTokenTransactionParams
val feeAmount = (transactionData.fee as Fee.Kaspa).revealTransactionFee
val redeemScript = RedeemScript(
wallet.publicKey.blockchainKey,
wallet.publicKey.blockchainKey.toCompressedPublicKey(),
incompleteTokenTransactionParams.envelope,
)
val transaction = transactionBuilder.buildKRC20RevealTransactionToSign(
Expand Down Expand Up @@ -461,7 +473,10 @@ internal class KaspaWalletManager(
return dataStorage.getOrNull(token.createKey())
}

private suspend fun store(token: Token, data: BlockchainSavedData.KaspaKRC20IncompleteTokenTransaction) {
private suspend fun storeIncompleteTokenTransaction(
token: Token,
data: BlockchainSavedData.KaspaKRC20IncompleteTokenTransaction,
) {
dataStorage.store(token.createKey(), data)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package com.tangem.blockchain.blockchains.kaspa.krc20
import com.tangem.blockchain.blockchains.kaspa.krc20.model.IncompleteTokenTransactionParams
import com.tangem.blockchain.common.TransactionExtras

data class KaspaKRC20TransactionExtras(
internal data class KaspaKRC20TransactionExtras(
val incompleteTokenTransactionParams: IncompleteTokenTransactionParams,
) : TransactionExtras
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.tangem.blockchain.blockchains.kaspa.krc20.model

import com.tangem.blockchain.blockchains.kaspa.KaspaTransaction

data class CommitTransaction(
internal data class CommitTransaction(
val transaction: KaspaTransaction,
val hashes: List<ByteArray>,
val redeemScript: RedeemScript,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class Envelope(
internal data class Envelope(
@Json(name = "p") val p: String,
@Json(name = "op") val op: String,
@Json(name = "amt") val amt: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.tangem.blockchain.blockchains.kaspa.krc20.model

import java.math.BigDecimal

data class IncompleteTokenTransactionParams(
internal data class IncompleteTokenTransactionParams(
val transactionId: String,
val amountValue: BigDecimal,
val feeAmountValue: BigDecimal,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.tangem.blockchain.blockchains.kaspa.krc20.model

data class RedeemScript(
internal data class RedeemScript(
val publicKey: ByteArray,
val envelope: Envelope,
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ interface AssetRequirementsManager {

suspend fun fulfillRequirements(currencyType: CryptoCurrencyType, signer: TransactionSigner): SimpleResult

suspend fun discardRequirements(currencyType: CryptoCurrencyType) { }
suspend fun discardRequirements(currencyType: CryptoCurrencyType): SimpleResult
}

0 comments on commit 6805bf4

Please sign in to comment.