From 001a2efc29b1acc6261cbc4cd5222f5dab1132a4 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 8 Oct 2025 16:36:36 +0500 Subject: [PATCH 1/5] refactor: rename RawTransactionRes->SignRawTransactionRes and RawTransactionRes->SignRawTransactionRes --- mm2src/coins/eth.rs | 41 +++++++++++---------- mm2src/coins/eth/eth_withdraw.rs | 1 + mm2src/coins/lightning.rs | 8 ++-- mm2src/coins/lp_coins.rs | 12 +++--- mm2src/coins/qrc20.rs | 6 +-- mm2src/coins/tendermint/tendermint_coin.rs | 15 ++++---- mm2src/coins/tendermint/tendermint_token.rs | 8 ++-- mm2src/coins/test_coin.rs | 6 +-- mm2src/coins/utxo/bch.rs | 6 +-- mm2src/coins/utxo/qtum.rs | 8 ++-- mm2src/coins/utxo/slp.rs | 6 +-- mm2src/coins/utxo/utxo_common.rs | 20 +++++----- mm2src/coins/utxo/utxo_standard.rs | 28 +++++++------- mm2src/coins/z_coin.rs | 2 +- 14 files changed, 86 insertions(+), 81 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 7261d4a24c..84b609a8b3 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -128,21 +128,22 @@ cfg_wasm32! { use super::{ coin_conf, lp_coinfind_or_err, AsyncMutex, BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, CoinProtocol, CoinTransportMetrics, CoinsContext, ConfirmPaymentInput, EthValidateFeeArgs, FeeApproxStage, - FoundSwapTxSpend, HistorySyncState, IguanaPrivKey, MarketCoinOps, MmCoin, MmCoinEnum, MyAddressError, - MyWalletAddress, NegotiateSwapContractAddrErr, NumConversError, NumConversResult, PaymentInstructionArgs, - PaymentInstructions, PaymentInstructionsErr, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, RawTransactionError, - RawTransactionFut, RawTransactionRequest, RawTransactionRes, RawTransactionResult, RefundPaymentArgs, RewardTarget, - RpcClientType, RpcTransportEventHandler, RpcTransportEventHandlerShared, SearchForSwapTxSpendInput, + FoundSwapTxSpend, GetRawTransactionRequest, HistorySyncState, IguanaPrivKey, MarketCoinOps, MmCoin, MmCoinEnum, + MyAddressError, MyWalletAddress, NegotiateSwapContractAddrErr, NumConversError, NumConversResult, + PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, + RawTransactionError, RawTransactionFut, RawTransactionResult, RefundPaymentArgs, RewardTarget, RpcClientType, + RpcTransportEventHandler, RpcTransportEventHandlerShared, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SignEthTransactionParams, SignRawTransactionEnum, - SignRawTransactionRequest, SignatureError, SignatureResult, SpendPaymentArgs, SwapGasFeePolicy, SwapOps, TradeFee, - TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, Transaction, TransactionDetails, - TransactionEnum, TransactionErr, TransactionFut, TransactionType, TxMarshalingErr, UnexpectedDerivationMethod, - ValidateAddressResult, ValidateFeeArgs, ValidateInstructionsErr, ValidateOtherPubKeyErr, ValidatePaymentError, - ValidatePaymentFut, ValidatePaymentInput, VerificationError, VerificationResult, WaitForHTLCTxSpendArgs, - WatcherOps, WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, - WatcherValidateTakerFeeInput, WeakSpawner, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest, - WithdrawResult, EARLY_CONFIRMATION_ERR_LOG, INVALID_CONTRACT_ADDRESS_ERR_LOG, INVALID_PAYMENT_STATE_ERR_LOG, - INVALID_RECEIVER_ERR_LOG, INVALID_SENDER_ERR_LOG, INVALID_SWAP_ID_ERR_LOG, + SignRawTransactionRequest, SignRawTransactionRes, SignatureError, SignatureResult, SpendPaymentArgs, + SwapGasFeePolicy, SwapOps, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, + Transaction, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, TransactionType, TxMarshalingErr, + UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, ValidateInstructionsErr, + ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentFut, ValidatePaymentInput, VerificationError, + VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps, WatcherReward, WatcherRewardError, + WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, WeakSpawner, + WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest, WithdrawResult, EARLY_CONFIRMATION_ERR_LOG, + INVALID_CONTRACT_ADDRESS_ERR_LOG, INVALID_PAYMENT_STATE_ERR_LOG, INVALID_RECEIVER_ERR_LOG, INVALID_SENDER_ERR_LOG, + INVALID_SWAP_ID_ERR_LOG, }; #[cfg(test)] pub(crate) use eth_utils::display_u256_with_decimal_point; @@ -1150,7 +1151,7 @@ impl EthCoinImpl { } } -async fn get_raw_transaction_impl(coin: EthCoin, req: RawTransactionRequest) -> RawTransactionResult { +async fn get_raw_transaction_impl(coin: EthCoin, req: GetRawTransactionRequest) -> RawTransactionResult { let tx = match req.tx_hash.strip_prefix("0x") { Some(tx) => tx, None => &req.tx_hash, @@ -1165,7 +1166,7 @@ async fn get_tx_hex_by_hash_impl(coin: EthCoin, tx_hash: H256) -> RawTransaction .await? .or_mm_err(|| RawTransactionError::HashNotExist(tx_hash.to_string()))?; let raw = signed_tx_from_web3_tx(web3_tx).map_to_mm(RawTransactionError::InternalError)?; - Ok(RawTransactionRes { + Ok(SignRawTransactionRes { tx_hex: BytesJson(rlp::encode(&raw).to_vec()), }) } @@ -2989,7 +2990,7 @@ async fn sign_raw_eth_tx(coin: &EthCoin, args: &SignEthTransactionParams) -> Raw my_address, ) .await - .map(|(signed_tx, _)| RawTransactionRes { + .map(|(signed_tx, _)| SignRawTransactionRes { tx_hex: signed_tx.tx_hex().into(), }) .map_to_mm(|err| RawTransactionError::TransactionError(err.get_plain_text_format())) @@ -3045,7 +3046,7 @@ async fn sign_raw_eth_tx(coin: &EthCoin, args: &SignEthTransactionParams) -> Raw .await .mm_err(|err| RawTransactionError::TransactionError(err.to_string()))?; - Ok(RawTransactionRes { + Ok(SignRawTransactionRes { tx_hex: signed_tx.tx_hex().into(), }) }, @@ -3535,6 +3536,7 @@ impl EthCoin { kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; existing_history.push(details); @@ -3908,6 +3910,7 @@ impl EthCoin { kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; existing_history.push(details); @@ -5959,7 +5962,7 @@ impl MmCoin for EthCoin { self.abortable_system.weak_spawner() } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { Box::new(get_raw_transaction_impl(self.clone(), req).boxed().compat()) } diff --git a/mm2src/coins/eth/eth_withdraw.rs b/mm2src/coins/eth/eth_withdraw.rs index e35a090799..0abacd3a22 100644 --- a/mm2src/coins/eth/eth_withdraw.rs +++ b/mm2src/coins/eth/eth_withdraw.rs @@ -406,6 +406,7 @@ where kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }) } } diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 8eb3107069..607de989b1 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -18,9 +18,9 @@ use crate::utxo::utxo_common::{big_decimal_from_sat, big_decimal_from_sat_unsign use crate::utxo::{sat_from_big_decimal, utxo_common, BlockchainNetwork}; use crate::{ BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, - HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions, - PaymentInstructionsErr, RawTransactionError, RawTransactionFut, RawTransactionRequest, RawTransactionResult, - RefundError, RefundPaymentArgs, RefundResult, SearchForSwapTxSpendInput, SendPaymentArgs, + GetRawTransactionRequest, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, + PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, RawTransactionError, RawTransactionFut, + RawTransactionResult, RefundError, RefundPaymentArgs, RefundResult, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, SignatureError, SignatureResult, SpendPaymentArgs, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, Transaction, TransactionEnum, TransactionErr, TransactionResult, TxMarshalingErr, UnexpectedDerivationMethod, UtxoStandardCoin, ValidateAddressResult, ValidateFeeArgs, @@ -1235,7 +1235,7 @@ impl MmCoin for LightningCoin { self.platform.abortable_system.weak_spawner() } - fn get_raw_transaction(&self, _req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, _req: GetRawTransactionRequest) -> RawTransactionFut<'_> { let fut = async move { MmError::err(RawTransactionError::InternalError( "get_raw_transaction method is not supported for lightning, please use get_payment_details method instead.".into(), diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 9c53c21648..e6a5f7aaeb 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -320,9 +320,9 @@ pub type TradePreimageFut = Box = Result>; pub type TxHistoryFut = Box> + Send>; pub type TxHistoryResult = Result>; -pub type RawTransactionResult = Result>; +pub type RawTransactionResult = Result>; pub type RawTransactionFut<'a> = - Box> + Send + 'a>; + Box> + Send + 'a>; pub type RefundResult = Result>; /// Helper type used for swap transactions' spend preimage generation result pub type GenPreimageResult = MmResult, TxGenError>; @@ -438,13 +438,13 @@ impl HttpStatusCode for GetMyAddressError { } #[derive(Deserialize)] -pub struct RawTransactionRequest { +pub struct GetRawTransactionRequest { pub coin: String, pub tx_hash: String, } #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct RawTransactionRes { +pub struct SignRawTransactionRes { /// Raw bytes of signed transaction in hexadecimal string, this should be return hexadecimal encoded signed transaction for get_raw_transaction pub tx_hex: BytesJson, } @@ -3606,7 +3606,7 @@ pub trait MmCoin: SwapOps + WatcherOps + MarketCoinOps + Send + Sync + 'static { fn withdraw(&self, req: WithdrawRequest) -> WithdrawFut; - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_>; + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_>; fn get_tx_hex_by_hash(&self, tx_hash: Vec) -> RawTransactionFut<'_>; @@ -5439,7 +5439,7 @@ pub async fn withdraw(ctx: MmArc, req: WithdrawRequest) -> WithdrawResult { coin.withdraw(req).compat().await } -pub async fn get_raw_transaction(ctx: MmArc, req: RawTransactionRequest) -> RawTransactionResult { +pub async fn get_raw_transaction(ctx: MmArc, req: GetRawTransactionRequest) -> RawTransactionResult { let coin = lp_coinfind_or_err(&ctx, &req.coin).await.map_mm_err()?; coin.get_raw_transaction(req).compat().await } diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 92f74fad59..7e91fa9feb 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -24,8 +24,8 @@ use crate::utxo::{ }; use crate::{ BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, ConfirmPaymentInput, DexFee, FeeApproxStage, - FoundSwapTxSpend, HistorySyncState, IguanaPrivKey, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, - PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, RawTransactionFut, RawTransactionRequest, RawTransactionResult, + FoundSwapTxSpend, GetRawTransactionRequest, HistorySyncState, IguanaPrivKey, MarketCoinOps, MmCoin, + NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, RawTransactionFut, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, SwapOps, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionData, TransactionDetails, TransactionEnum, TransactionErr, TransactionResult, TransactionType, @@ -1247,7 +1247,7 @@ impl MmCoin for Qrc20Coin { Box::new(qrc20_withdraw(self.clone(), req).boxed().compat()) } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { Box::new(utxo_common::get_raw_transaction(&self.utxo, req).boxed().compat()) } diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 702b028a43..605e12b07d 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -17,10 +17,10 @@ use crate::utxo::sat_from_big_decimal; use crate::utxo::utxo_common::big_decimal_from_sat; use crate::{ big_decimal_from_sat_unsigned, BalanceError, BalanceFut, BigDecimal, CheckIfMyPaymentSentArgs, CoinBalance, - ConfirmPaymentInput, DelegationError, DexFee, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, - MmCoin, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, PrivKeyPolicy, PrivKeyPolicyNotAllowed, - RawTransactionError, RawTransactionFut, RawTransactionRequest, RawTransactionRes, RawTransactionResult, - RefundPaymentArgs, RpcCommonOps, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, + ConfirmPaymentInput, DelegationError, DexFee, FeeApproxStage, FoundSwapTxSpend, GetRawTransactionRequest, + HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, PrivKeyPolicy, + PrivKeyPolicyNotAllowed, RawTransactionError, RawTransactionFut, RawTransactionResult, RefundPaymentArgs, + RpcCommonOps, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, SignRawTransactionRes, SignatureError, SignatureResult, SpendPaymentArgs, SwapOps, ToBytes, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionData, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, TransactionResult, TransactionType, TxFeeDetails, TxMarshalingErr, @@ -3459,17 +3459,18 @@ impl MmCoin for TendermintCoin { TransactionType::StandardTransfer }, memo: Some(memo), + rseeds: None, }) }; Box::new(fut.boxed().compat()) } - fn get_raw_transaction(&self, mut req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, mut req: GetRawTransactionRequest) -> RawTransactionFut<'_> { let coin = self.clone(); let fut = async move { req.tx_hash.make_ascii_uppercase(); let tx_from_rpc = coin.request_tx(req.tx_hash).await.map_mm_err()?; - Ok(RawTransactionRes { + Ok(SignRawTransactionRes { tx_hex: tx_from_rpc.encode_to_vec().into(), }) }; @@ -3485,7 +3486,7 @@ impl MmCoin for TendermintCoin { })?; let hash = hex::encode_upper(H256::from(hash)); let tx_from_rpc = coin.request_tx(hash).await.map_mm_err()?; - Ok(RawTransactionRes { + Ok(SignRawTransactionRes { tx_hex: tx_from_rpc.encode_to_vec().into(), }) }; diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index 95193fe520..416136bde1 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -10,9 +10,9 @@ use crate::hd_wallet::HDAddressSelector; use crate::utxo::utxo_common::big_decimal_from_sat; use crate::{ big_decimal_from_sat_unsigned, utxo::sat_from_big_decimal, BalanceFut, BigDecimal, CheckIfMyPaymentSentArgs, - CoinBalance, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, - MmCoin, MyAddressError, NegotiateSwapContractAddrErr, RawTransactionError, RawTransactionFut, - RawTransactionRequest, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, + CoinBalance, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, GetRawTransactionRequest, + HistorySyncState, MarketCoinOps, MmCoin, MyAddressError, NegotiateSwapContractAddrErr, RawTransactionError, + RawTransactionFut, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionDetails, TransactionEnum, TransactionErr, TransactionResult, TransactionType, TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, @@ -574,7 +574,7 @@ impl MmCoin for TendermintToken { Box::new(fut.boxed().compat()) } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { self.platform_coin.get_raw_transaction(req) } diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index ad24b86c7c..0887e65c0c 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -1,8 +1,8 @@ #![allow(clippy::all)] use super::{ - CoinBalance, CommonSwapOpsV2, FindPaymentSpendError, FundingTxSpend, HistorySyncState, MarketCoinOps, MmCoin, - RawTransactionFut, RawTransactionRequest, RefundTakerPaymentArgs, SearchForFundingSpendErr, SwapOps, TradeFee, + CoinBalance, CommonSwapOpsV2, FindPaymentSpendError, FundingTxSpend, GetRawTransactionRequest, HistorySyncState, + MarketCoinOps, MmCoin, RawTransactionFut, RefundTakerPaymentArgs, SearchForFundingSpendErr, SwapOps, TradeFee, TransactionEnum, TransactionFut, }; use crate::coin_errors::{AddressFromPubkeyError, ValidatePaymentResult}; @@ -415,7 +415,7 @@ impl MmCoin for TestCoin { unimplemented!() } - fn get_raw_transaction(&self, _req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, _req: GetRawTransactionRequest) -> RawTransactionFut<'_> { unimplemented!() } diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index caea216d58..1afc53e682 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -20,8 +20,8 @@ use crate::utxo::utxo_tx_history_v2::{ use crate::{ coin_balance, BlockHeightAndTime, CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinBalance, CoinBalanceMap, CoinProtocol, CoinWithDerivationMethod, CoinWithPrivKeyPolicy, ConfirmPaymentInput, DexFee, - GetWithdrawSenderAddress, IguanaBalanceOps, IguanaPrivKey, MmCoinEnum, NegotiateSwapContractAddrErr, - PrivKeyBuildPolicy, RawTransactionFut, RawTransactionRequest, RawTransactionResult, RefundPaymentArgs, + GetRawTransactionRequest, GetWithdrawSenderAddress, IguanaBalanceOps, IguanaPrivKey, MmCoinEnum, + NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, RawTransactionFut, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, SwapOps, TradePreimageValue, TransactionFut, TransactionResult, TransactionType, TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, @@ -1294,7 +1294,7 @@ impl MmCoin for BchCoin { self.as_ref().abortable_system.weak_spawner() } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { Box::new(utxo_common::get_raw_transaction(&self.utxo_arc, req).boxed().compat()) } diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index b444deb6f1..337268a760 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -31,9 +31,9 @@ use crate::utxo::utxo_tx_history_v2::{ }; use crate::{ eth, CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinBalance, CoinBalanceMap, CoinWithDerivationMethod, - CoinWithPrivKeyPolicy, ConfirmPaymentInput, DelegationError, DelegationFut, DexFee, GetWithdrawSenderAddress, - IguanaBalanceOps, IguanaPrivKey, MmCoinEnum, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, - RawTransactionRequest, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, + CoinWithPrivKeyPolicy, ConfirmPaymentInput, DelegationError, DelegationFut, DexFee, GetRawTransactionRequest, + GetWithdrawSenderAddress, IguanaBalanceOps, IguanaPrivKey, MmCoinEnum, NegotiateSwapContractAddrErr, + PrivKeyBuildPolicy, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, StakingInfosFut, SwapOps, TradePreimageValue, TransactionFut, TransactionResult, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, ValidateOtherPubKeyErr, ValidatePaymentError, @@ -911,7 +911,7 @@ impl MmCoin for QtumCoin { self.as_ref().abortable_system.weak_spawner() } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { Box::new(utxo_common::get_raw_transaction(&self.utxo_arc, req).boxed().compat()) } diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 63966089f5..d04d55b7b4 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -18,8 +18,8 @@ use crate::utxo::{ }; use crate::{ BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, ConfirmPaymentInput, DerivationMethod, DexFee, FeeApproxStage, - FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, NumConversError, - PrivKeyPolicyNotAllowed, RawTransactionFut, RawTransactionRequest, RawTransactionResult, RefundPaymentArgs, + FoundSwapTxSpend, GetRawTransactionRequest, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, + NumConversError, PrivKeyPolicyNotAllowed, RawTransactionFut, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionData, TransactionDetails, TransactionEnum, TransactionErr, TransactionResult, TxFeeDetails, @@ -1571,7 +1571,7 @@ impl MmCoin for SlpToken { self.conf.abortable_system.weak_spawner() } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { Box::new( utxo_common::get_raw_transaction(self.platform_coin.as_ref(), req) .boxed() diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index d1fe6e3561..f75959eb05 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -17,14 +17,14 @@ use crate::watcher_common::validate_watcher_reward; use crate::{ scan_for_new_addresses_impl, CanRefundHtlc, CoinBalance, CoinWithDerivationMethod, ConfirmPaymentInput, DexFee, DexFeeBurnDestination, GenPreimageResult, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, - GetWithdrawSenderAddress, RawTransactionError, RawTransactionRequest, RawTransactionRes, RawTransactionResult, + GetRawTransactionRequest, GetWithdrawSenderAddress, RawTransactionError, RawTransactionResult, RefundFundingSecretArgs, RefundMakerPaymentSecretArgs, RefundPaymentArgs, RewardTarget, SearchForSwapTxSpendInput, SendMakerPaymentArgs, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SendTakerFundingArgs, - SignRawTransactionEnum, SignRawTransactionRequest, SignUtxoTransactionParams, SignatureError, SignatureResult, - SpendMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, TradePreimageValue, TransactionData, - TransactionFut, TransactionResult, TxFeeDetails, TxGenError, TxMarshalingErr, TxPreimageWithSig, - ValidateAddressResult, ValidateOtherPubKeyErr, ValidatePaymentFut, ValidatePaymentInput, ValidateSwapV2TxError, - ValidateSwapV2TxResult, ValidateTakerFundingArgs, ValidateTakerFundingSpendPreimageError, + SignRawTransactionEnum, SignRawTransactionRequest, SignRawTransactionRes, SignUtxoTransactionParams, + SignatureError, SignatureResult, SpendMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, + TradePreimageValue, TransactionData, TransactionFut, TransactionResult, TxFeeDetails, TxGenError, TxMarshalingErr, + TxPreimageWithSig, ValidateAddressResult, ValidateOtherPubKeyErr, ValidatePaymentFut, ValidatePaymentInput, + ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, ValidateTakerFundingSpendPreimageError, ValidateTakerFundingSpendPreimageResult, ValidateTakerPaymentSpendPreimageError, ValidateTakerPaymentSpendPreimageResult, ValidateWatcherSpendInput, VerificationError, VerificationResult, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, WithdrawResult, @@ -3287,7 +3287,7 @@ async fn sign_raw_utxo_tx + UtxoTxGenerationOps>( .map_err(|err| RawTransactionError::SigningError(err.to_string()))?; let tx_signed_bytes = serialize_with_flags(&tx_signed, SERIALIZE_TRANSACTION_WITNESS); - Ok(RawTransactionRes { + Ok(SignRawTransactionRes { tx_hex: tx_signed_bytes.into(), }) } @@ -3456,7 +3456,7 @@ pub const fn should_burn_dex_fee() -> bool { false } // TODO: fix back to true when negotiation version added -pub async fn get_raw_transaction(coin: &UtxoCoinFields, req: RawTransactionRequest) -> RawTransactionResult { +pub async fn get_raw_transaction(coin: &UtxoCoinFields, req: GetRawTransactionRequest) -> RawTransactionResult { let hash = H256Json::from_str(&req.tx_hash).map_to_mm(|e| RawTransactionError::InvalidHashError(e.to_string()))?; let hex = coin .rpc_client @@ -3464,7 +3464,7 @@ pub async fn get_raw_transaction(coin: &UtxoCoinFields, req: RawTransactionReque .compat() .await .map_err(|e| RawTransactionError::Transport(e.to_string()))?; - Ok(RawTransactionRes { tx_hex: hex }) + Ok(SignRawTransactionRes { tx_hex: hex }) } pub async fn get_tx_hex_by_hash(coin: &UtxoCoinFields, tx_hash: Vec) -> RawTransactionResult { @@ -3479,7 +3479,7 @@ pub async fn get_tx_hex_by_hash(coin: &UtxoCoinFields, tx_hash: Vec) -> RawT .compat() .await .map_err(|e| RawTransactionError::Transport(e.to_string()))?; - Ok(RawTransactionRes { tx_hex: hex }) + Ok(SignRawTransactionRes { tx_hex: hex }) } pub async fn withdraw(coin: T, req: WithdrawRequest) -> WithdrawResult diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 9c31818bb9..28195e8c8a 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -33,19 +33,19 @@ use crate::utxo::utxo_tx_history_v2::{ use crate::{ CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinBalance, CoinBalanceMap, CoinWithDerivationMethod, CoinWithPrivKeyPolicy, CommonSwapOpsV2, ConfirmPaymentInput, DexFee, FindPaymentSpendError, FundingTxSpend, - GenPreimageResult, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, GetWithdrawSenderAddress, IguanaBalanceOps, - IguanaPrivKey, MakerCoinSwapOpsV2, MmCoinEnum, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, - RawTransactionRequest, RawTransactionResult, RefundFundingSecretArgs, RefundMakerPaymentSecretArgs, - RefundMakerPaymentTimelockArgs, RefundPaymentArgs, RefundTakerPaymentArgs, SearchForFundingSpendErr, - SearchForSwapTxSpendInput, SendMakerPaymentArgs, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, - SendTakerFundingArgs, SignRawTransactionRequest, SignatureResult, SpendMakerPaymentArgs, SpendPaymentArgs, SwapOps, - SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, TradePreimageValue, TransactionFut, TransactionResult, - TxMarshalingErr, TxPreimageWithSig, ValidateAddressResult, ValidateFeeArgs, ValidateMakerPaymentArgs, - ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentFut, ValidatePaymentInput, ValidateSwapV2TxResult, - ValidateTakerFundingArgs, ValidateTakerFundingSpendPreimageResult, ValidateTakerPaymentSpendPreimageResult, - ValidateWatcherSpendInput, VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps, WatcherReward, - WatcherRewardError, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, - WithdrawFut, + GenPreimageResult, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, GetRawTransactionRequest, + GetWithdrawSenderAddress, IguanaBalanceOps, IguanaPrivKey, MakerCoinSwapOpsV2, MmCoinEnum, + NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, RawTransactionResult, RefundFundingSecretArgs, + RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, RefundPaymentArgs, RefundTakerPaymentArgs, + SearchForFundingSpendErr, SearchForSwapTxSpendInput, SendMakerPaymentArgs, SendMakerPaymentSpendPreimageInput, + SendPaymentArgs, SendTakerFundingArgs, SignRawTransactionRequest, SignatureResult, SpendMakerPaymentArgs, + SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, TradePreimageValue, + TransactionFut, TransactionResult, TxMarshalingErr, TxPreimageWithSig, ValidateAddressResult, ValidateFeeArgs, + ValidateMakerPaymentArgs, ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentFut, ValidatePaymentInput, + ValidateSwapV2TxResult, ValidateTakerFundingArgs, ValidateTakerFundingSpendPreimageResult, + ValidateTakerPaymentSpendPreimageResult, ValidateWatcherSpendInput, VerificationResult, WaitForHTLCTxSpendArgs, + WatcherOps, WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, + WatcherValidateTakerFeeInput, WithdrawFut, }; use bitcrypto::sign_message_hash; use common::executor::{AbortableSystem, AbortedError}; @@ -986,7 +986,7 @@ impl MmCoin for UtxoStandardCoin { self.as_ref().abortable_system.weak_spawner() } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { Box::new(utxo_common::get_raw_transaction(&self.utxo_arc, req).boxed().compat()) } diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 0cb179b756..90e49b6814 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1763,7 +1763,7 @@ impl MmCoin for ZCoin { )))) } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { Box::new(utxo_common::get_raw_transaction(&self.utxo_arc, req).boxed().compat()) } From 14e00248206f023bcfe1d5945e9803545aafea6f Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 8 Oct 2025 16:42:22 +0500 Subject: [PATCH 2/5] fix(zcoin): add locked notes handling for withdrawals (post PR 2331) --- mm2src/coins/lp_coins.rs | 27 ++++++- mm2src/coins/my_tx_history_v2.rs | 1 + mm2src/coins/qrc20.rs | 1 + mm2src/coins/qrc20/qrc20_tests.rs | 3 + mm2src/coins/rpc_command/consolidate_utxos.rs | 1 + mm2src/coins/tendermint/tendermint_coin.rs | 3 + mm2src/coins/tendermint/tendermint_token.rs | 1 + .../tendermint/tendermint_tx_history_v2.rs | 1 + mm2src/coins/utxo/qtum_delegation.rs | 1 + mm2src/coins/utxo/slp.rs | 1 + mm2src/coins/utxo/utxo_common.rs | 1 + mm2src/coins/utxo/utxo_withdraw.rs | 1 + mm2src/coins/z_coin.rs | 75 +++++++++++++------ .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 3 +- mm2src/mm2_test_helpers/src/structs.rs | 1 + 15 files changed, 97 insertions(+), 24 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index e6a5f7aaeb..6d456d4fd1 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -2505,6 +2505,18 @@ impl KmdRewardsDetails { } } +/// Request to send zcoin raw transaction with extra parameters +#[derive(Clone, Debug, Deserialize)] +pub struct ZcoinSendRawTransactionRequest { + coin: String, + /// List of rseeds used to create transaction notes, needed to lock sent notes properly + pub rseeds: Vec, + /// Change amount + pub received_by_me: BigDecimal, + /// Serialized zcoin transaction + pub tx_hex: String, +} + #[derive(Default, Clone, Debug, Deserialize, PartialEq, Serialize)] pub enum TransactionType { StakingDelegation, @@ -2538,7 +2550,7 @@ pub struct TransactionDetails { /// The amount spent from "my" address spent_by_me: BigDecimal, /// The amount received by "my" address - received_by_me: BigDecimal, + pub received_by_me: BigDecimal, /// Resulting "my" balance change my_balance_change: BigDecimal, /// Block height @@ -2560,6 +2572,8 @@ pub struct TransactionDetails { #[serde(default)] transaction_type: TransactionType, memo: Option, + /// List of rseeds, for Zcoin + pub rseeds: Option>, } #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] @@ -5476,6 +5490,17 @@ pub async fn sign_raw_transaction(ctx: MmArc, req: SignRawTransactionRequest) -> coin.sign_raw_tx(&req).await } +pub async fn z_send_raw_transaction( + ctx: MmArc, + req: ZcoinSendRawTransactionRequest, +) -> MmResult { + let coin = lp_coinfind_or_err(&ctx, &req.coin).await.map_mm_err()?; + match coin { + MmCoinEnum::ZCoin(ref z_coin) => z_coin.z_send_raw_tx(req).await, + _ => MmError::err(RawTransactionError::NotImplemented { coin: req.coin }), + } +} + pub async fn remove_delegation(ctx: MmArc, req: RemoveDelegateRequest) -> DelegationResult { let coin = lp_coinfind_or_err(&ctx, &req.coin).await.map_mm_err()?; diff --git a/mm2src/coins/my_tx_history_v2.rs b/mm2src/coins/my_tx_history_v2.rs index da957e2179..a585ff131f 100644 --- a/mm2src/coins/my_tx_history_v2.rs +++ b/mm2src/coins/my_tx_history_v2.rs @@ -250,6 +250,7 @@ impl<'a, Addr: Clone + DisplayAddress + Eq + std::hash::Hash, Tx: Transaction> T kmd_rewards: None, transaction_type: self.transaction_type, memo: None, + rseeds: None, } } } diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 7e91fa9feb..16b527e658 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1571,6 +1571,7 @@ async fn qrc20_withdraw(coin: Qrc20Coin, req: WithdrawRequest) -> WithdrawResult kmd_rewards: None, transaction_type: TransactionType::StandardTransfer, memo: None, + rseeds: None, }) } diff --git a/mm2src/coins/qrc20/qrc20_tests.rs b/mm2src/coins/qrc20/qrc20_tests.rs index 335ab4320e..8173ebedcb 100644 --- a/mm2src/coins/qrc20/qrc20_tests.rs +++ b/mm2src/coins/qrc20/qrc20_tests.rs @@ -630,6 +630,7 @@ fn test_transfer_details_by_hash() { kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; assert_eq!(actual, expected); @@ -654,6 +655,7 @@ fn test_transfer_details_by_hash() { kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; assert_eq!(actual, expected); @@ -702,6 +704,7 @@ fn test_transfer_details_by_hash() { kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; assert_eq!(actual, expected); assert!(it.next().is_none()); diff --git a/mm2src/coins/rpc_command/consolidate_utxos.rs b/mm2src/coins/rpc_command/consolidate_utxos.rs index 8a55fe6328..a201c889a1 100644 --- a/mm2src/coins/rpc_command/consolidate_utxos.rs +++ b/mm2src/coins/rpc_command/consolidate_utxos.rs @@ -139,6 +139,7 @@ pub async fn consolidate_utxos_rpc( kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; if tx.should_update_kmd_rewards() { diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 605e12b07d..df69e8ecf3 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -2745,6 +2745,7 @@ impl TendermintCoin { kmd_rewards: None, transaction_type: TransactionType::StakingDelegation, memo: Some(req.memo), + rseeds: None, }) } @@ -2874,6 +2875,7 @@ impl TendermintCoin { kmd_rewards: None, transaction_type: TransactionType::RemoveDelegation, memo: Some(req.memo), + rseeds: None, }) } @@ -3074,6 +3076,7 @@ impl TendermintCoin { kmd_rewards: None, transaction_type: TransactionType::ClaimDelegationRewards, memo: Some(req.memo), + rseeds: None, }) } diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index 416136bde1..4951d36000 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -569,6 +569,7 @@ impl MmCoin for TendermintToken { TransactionType::TokenTransfer(token.token_id()) }, memo: Some(memo), + rseeds: None, }) }; Box::new(fut.boxed().compat()) diff --git a/mm2src/coins/tendermint/tendermint_tx_history_v2.rs b/mm2src/coins/tendermint/tendermint_tx_history_v2.rs index 65418b8696..6057add35d 100644 --- a/mm2src/coins/tendermint/tendermint_tx_history_v2.rs +++ b/mm2src/coins/tendermint/tendermint_tx_history_v2.rs @@ -975,6 +975,7 @@ where kmd_rewards: None, transaction_type, memo: Some(deserialized_tx.body.memo.clone()), + rseeds: None, }; tx_details.push(details.clone()); diff --git a/mm2src/coins/utxo/qtum_delegation.rs b/mm2src/coins/utxo/qtum_delegation.rs index f521f80c3e..444d4fb099 100644 --- a/mm2src/coins/utxo/qtum_delegation.rs +++ b/mm2src/coins/utxo/qtum_delegation.rs @@ -351,6 +351,7 @@ impl QtumCoin { kmd_rewards: None, transaction_type, memo: None, + rseeds: None, }) } diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index d04d55b7b4..662fdfbd12 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1705,6 +1705,7 @@ impl MmCoin for SlpToken { kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; Ok(details) }; diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index f75959eb05..a4a4c515ac 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -4172,6 +4172,7 @@ pub async fn tx_details_by_hash( kmd_rewards, transaction_type: Default::default(), memo: None, + rseeds: None, }) } diff --git a/mm2src/coins/utxo/utxo_withdraw.rs b/mm2src/coins/utxo/utxo_withdraw.rs index 1d56867eda..64eff284d2 100644 --- a/mm2src/coins/utxo/utxo_withdraw.rs +++ b/mm2src/coins/utxo/utxo_withdraw.rs @@ -241,6 +241,7 @@ where kmd_rewards: data.kmd_rewards, transaction_type: Default::default(), memo: None, + rseeds: None, }) } } diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 90e49b6814..3dec671187 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -33,14 +33,15 @@ use crate::z_coin::storage::{BlockDbImpl, LockedNotesStorage, WalletDbShared}; use crate::z_coin::z_tx_history::{fetch_tx_history_from_db, ZCoinTxHistoryItem}; use crate::{ BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, ConfirmPaymentInput, DexFee, FeeApproxStage, - FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, NumConversError, - PrivKeyActivationPolicy, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, RawTransactionFut, RawTransactionRequest, - RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, - SignatureError, SignatureResult, SpendPaymentArgs, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, - TradePreimageValue, Transaction, TransactionData, TransactionDetails, TransactionEnum, TransactionResult, - TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, - ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentInput, VerificationError, VerificationResult, - WaitForHTLCTxSpendArgs, WatcherOps, WeakSpawner, WithdrawError, WithdrawFut, WithdrawRequest, + FoundSwapTxSpend, GetRawTransactionRequest, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, + NumConversError, PrivKeyActivationPolicy, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, RawTransactionError, + RawTransactionFut, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, + SignRawTransactionRequest, SignatureError, SignatureResult, SpendPaymentArgs, SwapOps, TradeFee, TradePreimageFut, + TradePreimageResult, TradePreimageValue, Transaction, TransactionData, TransactionDetails, TransactionEnum, + TransactionResult, TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, + ValidateFeeArgs, ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentInput, VerificationError, + VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps, WeakSpawner, WithdrawError, WithdrawFut, WithdrawRequest, + ZcoinSendRawTransactionRequest, }; use crate::z_coin::storage::z_locked_notes::LockedNote; @@ -66,6 +67,7 @@ use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; #[cfg(test)] use mocktopus::macros::*; +use num_traits::Zero; use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json, H264 as H264Json}; use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use serde_json::Value as Json; @@ -753,6 +755,43 @@ impl ZCoin { } Ok(true) } + + pub async fn z_send_raw_tx(&self, req: ZcoinSendRawTransactionRequest) -> MmResult { + let tx_bytes = hex::decode(req.tx_hex.clone())?; + let z_tx = + ZTransaction::read(tx_bytes.as_slice()).map_err(|err| RawTransactionError::DecodeError(err.to_string()))?; + + let mut sync_guard = self + .wait_for_gen_tx_blockchain_sync() + .await + .mm_err(|err| RawTransactionError::InternalError(err.to_string())) + .map_mm_err()?; + let tx_hash = utxo_common::send_raw_tx(self.as_ref(), &req.tx_hex) + .compat() + .await + .map_err(|err| RawTransactionError::TransactionError(err))?; + + for rseed in req.rseeds { + self.z_fields + .locked_notes_db + .insert_spent_note(z_tx.txid().to_string(), rseed) + .await + .mm_err(|err| RawTransactionError::InternalError(err.to_string())) + .map_mm_err()?; + } + + if req.received_by_me > BigDecimal::zero() { + let received_by_me = sat_from_big_decimal(&req.received_by_me, self.as_ref().decimals).map_mm_err()?; + self.z_fields + .locked_notes_db + .insert_change_note(z_tx.txid().to_string(), received_by_me) + .await + .mm_err(|err| RawTransactionError::InternalError(err.to_string())) + .map_mm_err()?; + } + sync_guard.respawn_guard.watch_for_tx(z_tx.txid()); + Ok(tx_hash) + } } impl AsRef for ZCoin { @@ -1309,22 +1348,13 @@ impl MarketCoinOps for ZCoin { self.ticker() } - fn send_raw_tx(&self, tx: &str) -> Box + Send> { - let tx_bytes = try_fus!(hex::decode(tx)); - let z_tx = try_fus!(ZTransaction::read(tx_bytes.as_slice())); - - let this = self.clone(); - let tx = tx.to_owned(); - - let fut = async move { - let mut sync_guard = try_s!(this.wait_for_gen_tx_blockchain_sync().await); - let tx_hash = utxo_common::send_raw_tx(this.as_ref(), &tx).compat().await?; - sync_guard.respawn_guard.watch_for_tx(z_tx.txid()); - Ok(tx_hash) - }; + fn send_raw_tx(&self, _tx: &str) -> Box + Send> { + let fut = async move { Err("Not implemented, use z_send_raw_transaction rpc".to_string()) }; Box::new(fut.boxed().compat()) } + /// This function is used for rebroadcasting transaction by seed nodes + /// For broadcasting z_transactions locally z_send_raw_tx should be used fn send_raw_tx_bytes(&self, tx: &[u8]) -> Box + Send> { let z_tx = try_fus!(ZTransaction::read(tx)); @@ -2098,7 +2128,7 @@ impl InitWithdrawCoin for ZCoin { memo, }; - let GenTxData { tx, data, .. } = self.gen_tx(vec![], vec![z_output]).await.map_mm_err()?; + let GenTxData { tx, data, rseeds, .. } = self.gen_tx(vec![], vec![z_output]).await.map_mm_err()?; let mut tx_bytes = Vec::with_capacity(1024); tx.write(&mut tx_bytes) .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; @@ -2128,6 +2158,7 @@ impl InitWithdrawCoin for ZCoin { kmd_rewards: None, transaction_type: Default::default(), memo: req.memo, + rseeds: Some(rseeds), }) } } diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index c724175f45..48324bfb22 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -66,7 +66,7 @@ use coins::z_coin::ZCoin; use coins::{ add_delegation, claim_staking_rewards, delegations_info, get_my_address, get_raw_transaction, get_swap_gas_fee_policy, nft, ongoing_undelegations_info, remove_delegation, set_swap_gas_fee_policy, sign_message, - sign_raw_transaction, validators_info, verify_message, withdraw, + sign_raw_transaction, validators_info, verify_message, withdraw, z_send_raw_transaction, }; use coins_activation::{ cancel_init_l2, cancel_init_platform_coin_with_tokens, cancel_init_standalone_coin, cancel_init_token, @@ -280,6 +280,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, remove_node_from_version_stat).await, "sign_message" => handle_mmrpc(ctx, request, sign_message).await, "sign_raw_transaction" => handle_mmrpc(ctx, request, sign_raw_transaction).await, + "z_send_raw_transaction" => handle_mmrpc(ctx, request, z_send_raw_transaction).await, "start_simple_market_maker_bot" => handle_mmrpc(ctx, request, start_simple_market_maker_bot).await, "start_version_stat_collection" => handle_mmrpc(ctx, request, start_version_stat_collection).await, "stop_simple_market_maker_bot" => handle_mmrpc(ctx, request, stop_simple_market_maker_bot).await, diff --git a/mm2src/mm2_test_helpers/src/structs.rs b/mm2src/mm2_test_helpers/src/structs.rs index 819b819486..584c7eaee3 100644 --- a/mm2src/mm2_test_helpers/src/structs.rs +++ b/mm2src/mm2_test_helpers/src/structs.rs @@ -486,6 +486,7 @@ pub struct TransactionDetails { pub internal_id: String, pub transaction_type: TransactionType, pub memo: Option, + pub rseeds: Option>, } #[derive(Debug, Deserialize)] From 8fe5b5fff8599fdd185e3141da1433c3259ce2dc Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 8 Oct 2025 17:35:18 +0500 Subject: [PATCH 3/5] fix(tests): more rename to GetRawTransactionRequest fixes --- mm2src/coins/qrc20/qrc20_tests.rs | 2 ++ mm2src/coins/siacoin.rs | 19 ++++++++++--------- mm2src/coins/solana/solana_coin.rs | 6 +++--- mm2src/coins/solana/solana_token.rs | 10 ++++------ 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/mm2src/coins/qrc20/qrc20_tests.rs b/mm2src/coins/qrc20/qrc20_tests.rs index 8173ebedcb..0d870f1320 100644 --- a/mm2src/coins/qrc20/qrc20_tests.rs +++ b/mm2src/coins/qrc20/qrc20_tests.rs @@ -606,6 +606,7 @@ fn test_transfer_details_by_hash() { kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; assert_eq!(actual, expected); @@ -680,6 +681,7 @@ fn test_transfer_details_by_hash() { kmd_rewards: None, transaction_type: Default::default(), memo: None, + rseeds: None, }; assert_eq!(actual, expected); diff --git a/mm2src/coins/siacoin.rs b/mm2src/coins/siacoin.rs index e6d4e6b4e6..9d0c563941 100644 --- a/mm2src/coins/siacoin.rs +++ b/mm2src/coins/siacoin.rs @@ -1,16 +1,17 @@ use super::{ - BalanceError, CoinBalance, HistorySyncState, MarketCoinOps, MmCoin, RawTransactionFut, RawTransactionRequest, - SwapOps, TradeFee, TransactionEnum, + BalanceError, CoinBalance, HistorySyncState, MarketCoinOps, MmCoin, RawTransactionFut, SwapOps, TradeFee, + TransactionEnum, }; use crate::hd_wallet::HDAddressSelector; use crate::{ coin_errors::MyAddressError, AddressFromPubkeyError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, - ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, - PrivKeyPolicy, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, - SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, TradePreimageFut, TradePreimageResult, - TradePreimageValue, TransactionResult, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, - ValidateFeeArgs, ValidateOtherPubKeyErr, ValidatePaymentInput, ValidatePaymentResult, VerificationResult, - WaitForHTLCTxSpendArgs, WatcherOps, WeakSpawner, WithdrawFut, WithdrawRequest, + ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, GetRawTransactionRequest, + NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, PrivKeyPolicy, RawTransactionResult, RefundPaymentArgs, + SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, + TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionResult, TxMarshalingErr, + UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, ValidateOtherPubKeyErr, ValidatePaymentInput, + ValidatePaymentResult, VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps, WeakSpawner, WithdrawFut, + WithdrawRequest, }; use crate::{SignatureError, VerificationError}; use async_trait::async_trait; @@ -243,7 +244,7 @@ impl MmCoin for SiaCoin { unimplemented!() } - fn get_raw_transaction(&self, _req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, _req: GetRawTransactionRequest) -> RawTransactionFut<'_> { unimplemented!() } diff --git a/mm2src/coins/solana/solana_coin.rs b/mm2src/coins/solana/solana_coin.rs index bb99d0ff87..a771c909b9 100644 --- a/mm2src/coins/solana/solana_coin.rs +++ b/mm2src/coins/solana/solana_coin.rs @@ -32,8 +32,8 @@ use crate::{ coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentResult}, hd_wallet::HDAddressSelector, BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, ConfirmPaymentInput, DexFee, FeeApproxStage, - FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, - RawTransactionFut, RawTransactionRequest, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, + FoundSwapTxSpend, GetRawTransactionRequest, HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, + PrivKeyBuildPolicy, RawTransactionFut, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionEnum, TransactionResult, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, ValidateOtherPubKeyErr, ValidatePaymentInput, @@ -235,7 +235,7 @@ impl MmCoin for SolanaCoin { todo!() } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { todo!() } diff --git a/mm2src/coins/solana/solana_token.rs b/mm2src/coins/solana/solana_token.rs index 92939b7dda..d75b336f94 100644 --- a/mm2src/coins/solana/solana_token.rs +++ b/mm2src/coins/solana/solana_token.rs @@ -19,12 +19,10 @@ use serde::Deserialize; use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentResult}; use crate::hd_wallet::HDAddressSelector; +use crate::{solana::SolanaCoin, BalanceFut, CoinBalance, RawTransactionFut, WithdrawFut, WithdrawRequest}; use crate::{ - solana::SolanaCoin, BalanceFut, CoinBalance, RawTransactionFut, RawTransactionRequest, WithdrawFut, WithdrawRequest, -}; -use crate::{ - CheckIfMyPaymentSentArgs, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, - MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, RawTransactionResult, RefundPaymentArgs, + CheckIfMyPaymentSentArgs, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, GetRawTransactionRequest, + HistorySyncState, MarketCoinOps, MmCoin, NegotiateSwapContractAddrErr, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionEnum, TransactionResult, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, ValidateOtherPubKeyErr, @@ -139,7 +137,7 @@ impl MmCoin for SolanaToken { todo!() } - fn get_raw_transaction(&self, req: RawTransactionRequest) -> RawTransactionFut<'_> { + fn get_raw_transaction(&self, req: GetRawTransactionRequest) -> RawTransactionFut<'_> { todo!() } From 5116e1afa643a369354427fdbd10378bad4ded66 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 8 Oct 2025 17:36:13 +0500 Subject: [PATCH 4/5] add test to check locked notes handling for withdrawals --- mm2src/coins/z_coin.rs | 77 ++++++++++++++++++- .../tests/docker_tests/z_coin_docker_tests.rs | 74 +++++++++++++++++- 2 files changed, 147 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 3dec671187..46ea75a36a 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -769,7 +769,7 @@ impl ZCoin { let tx_hash = utxo_common::send_raw_tx(self.as_ref(), &req.tx_hex) .compat() .await - .map_err(|err| RawTransactionError::TransactionError(err))?; + .map_err(RawTransactionError::TransactionError)?; for rseed in req.rseeds { self.z_fields @@ -2163,6 +2163,79 @@ impl InitWithdrawCoin for ZCoin { } } +impl ZCoin { + #[cfg(feature = "run-docker-tests")] + pub async fn withdraw_for_tests(&self, req: WithdrawRequest) -> Result> { + if req.fee.is_some() { + return MmError::err(WithdrawError::UnsupportedError( + "Setting a custom withdraw fee is not supported for ZCoin yet".to_owned(), + )); + } + + if req.from.is_some() { + return MmError::err(WithdrawError::UnsupportedError( + "Withdraw from a specific address is not supported for ZCoin yet".to_owned(), + )); + } + + let to_addr = decode_payment_address(z_mainnet_constants::HRP_SAPLING_PAYMENT_ADDRESS, &req.to) + .map_to_mm(|e| WithdrawError::InvalidAddress(format!("{e}")))? + .or_mm_err(|| WithdrawError::InvalidAddress(format!("Address {} decoded to None", req.to)))?; + let amount = if req.max { + let fee = self.get_one_kbyte_tx_fee().await.map_mm_err()?; + let balance = self.my_balance().compat().await.map_mm_err()?; + balance.spendable - fee + } else { + req.amount + }; + let satoshi = sat_from_big_decimal(&amount, self.decimals()).map_mm_err()?; + + let memo = req.memo.as_deref().map(interpret_memo_string).transpose()?; + let z_output = ZOutput { + to_addr, + amount: Amount::from_u64(satoshi) + .map_to_mm(|_| NumConversError(format!("Failed to get ZCash amount from {amount}"))) + .map_mm_err()?, + // TODO add optional viewing_key and memo fields to the WithdrawRequest + viewing_key: Some(self.z_fields.evk.fvk.ovk), + memo, + }; + + let GenTxData { tx, data, rseeds, .. } = self.gen_tx(vec![], vec![z_output]).await.map_mm_err()?; + let mut tx_bytes = Vec::with_capacity(1024); + tx.write(&mut tx_bytes) + .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; + let mut tx_hash = tx.txid().0.to_vec(); + tx_hash.reverse(); + + let received_by_me = big_decimal_from_sat_unsigned(data.received_by_me, self.decimals()); + let spent_by_me = big_decimal_from_sat_unsigned(data.spent_by_me, self.decimals()); + let tx_hash_hex = hex::encode(&tx_hash); + + Ok(TransactionDetails { + tx: TransactionData::new_signed(tx_bytes.into(), tx_hash_hex), + from: vec![self.z_fields.my_z_addr_encoded.clone()], + to: vec![req.to], + my_balance_change: &received_by_me - &spent_by_me, + total_amount: spent_by_me.clone(), + spent_by_me, + received_by_me, + block_height: 0, + timestamp: 0, + fee_details: Some(TxFeeDetails::Utxo(UtxoFeeDetails { + coin: Some(self.ticker().to_owned()), + amount: big_decimal_from_sat_unsigned(data.fee_amount, self.decimals()), + })), + coin: self.ticker().to_owned(), + internal_id: tx_hash.into(), + kmd_rewards: None, + transaction_type: Default::default(), + memo: req.memo, + rseeds: Some(rseeds), + }) + } +} + /// Waits until there are enough _unlocked_ Sapling notes to cover `total_required`. /// TODO: Consider adding `wait_until` argument. /// TODO: Integrate this into `light_wallet_db_sync_loop` instead of having a separate function. @@ -2211,7 +2284,7 @@ async fn wait_for_spendable_balance_impl( let sum_available = u64::from(sum_available); let sum_available = big_decimal_from_sat_unsigned(sum_available, selfi.decimals()); - // Reteurn InsufficientBalance error when all notes are unlocked but amount is insufficient. + // Return InsufficientBalance error when all notes are unlocked but amount is insufficient. if sum_available < total_required && unlocked_notes_len == wallet_notes_len { return MmError::err(GenTxError::InsufficientBalance { coin: selfi.ticker().to_string(), diff --git a/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs index 1e9b366fc3..b53c0e011a 100644 --- a/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs @@ -1,17 +1,21 @@ +use crate::common::Future01CompatExt; use bitcrypto::dhash160; use coins::z_coin::{ z_coin_from_conf_and_params_with_docker, z_send_dex_fee, ZCoin, ZcoinActivationParams, ZcoinRpcMode, }; -use coins::DexFeeBurnDestination; +use coins::MarketCoinOps; +use coins::WithdrawRequest; use coins::{ coin_errors::ValidatePaymentError, CoinProtocol, DexFee, PrivKeyBuildPolicy, RefundPaymentArgs, SendPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, ValidateFeeArgs, }; +use coins::{DexFeeBurnDestination, ZcoinSendRawTransactionRequest}; use common::now_sec; use lazy_static::lazy_static; use mm2_core::mm_ctx::{MmArc, MmCtxBuilder}; -use mm2_number::MmNumber; +use mm2_number::{BigDecimal, MmNumber}; use mm2_test_helpers::for_tests::zombie_conf_for_docker; +use num_traits::Zero; use tempfile::TempDir; use tokio::sync::Mutex; @@ -67,6 +71,72 @@ async fn prepare_zombie_sapling_cache() { drop(_lock) } +#[tokio::test(flavor = "current_thread")] +async fn zombie_coin_withdraw_and_send_maker_payment() { + let _lock = GEN_TX_LOCK_MUTEX.lock().await; + let (_ctx, coin) = z_coin_from_spending_key("secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe", "fe").await; + + assert!(coin.is_sapling_state_synced().await); + + // wait tx balance to mine: + for retries in 0.. { + let balance = coin.my_balance().compat().await; + println!("zombie_coin balance={:?}", balance); + if balance.unwrap().spendable > BigDecimal::zero() { + break; + } + assert!(retries < 60, "balance empty"); + tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; + } + + let withdraw_res = coin + .withdraw_for_tests( + serde_json::from_value::(json!({ + "amount": "10.0", + "to": "zs1hq65fswcur3uxe385cxxgynf37qz4jpfcj52sj9ndvfhc569qwd39alfv9k82e0zftp3xc2jfgj", + "coin": "ZOMBIE" + })) + .expect("expected valid WithdrawRequest"), + ) + .await; + assert!(withdraw_res.is_ok()); + + let send_tx_res = coin + .z_send_raw_tx( + serde_json::from_value::(json!({ + "coin": "ZOMBIE", + "rseeds": withdraw_res.as_ref().unwrap().rseeds.as_ref().unwrap(), + "received_by_me": withdraw_res.as_ref().unwrap().received_by_me, + "tx_hex": format!("{:x}", withdraw_res.as_ref().unwrap().tx.tx_hex().unwrap()), + })) + .expect("expected valid ZcoinSendRawTransactionRequest"), + ) + .await; + assert!(send_tx_res.is_ok()); + + let time_lock = now_sec() - 3600; + let secret_hash = [0; 20]; + let maker_uniq_data = [3; 32]; + let taker_uniq_data = [5; 32]; + let taker_key_pair = coin.derive_htlc_key_pair(taker_uniq_data.as_slice()); + let taker_pub = taker_key_pair.public(); + let args = SendPaymentArgs { + time_lock_duration: 0, + time_lock, + other_pubkey: taker_pub, + secret_hash: &secret_hash, + amount: "0.01".parse().unwrap(), + swap_contract_address: &None, + swap_unique_data: maker_uniq_data.as_slice(), + payment_instructions: &None, + watcher_reward: None, + wait_for_confirmation_until: 0, + }; + let tx = coin.send_maker_payment(args).await.unwrap(); + log!("payment tx {}", hex::encode(tx.tx_hash_as_bytes().0)); + drop(_lock); +} + #[tokio::test(flavor = "current_thread")] async fn zombie_coin_send_and_refund_maker_payment() { let _lock = GEN_TX_LOCK_MUTEX.lock().await; From 84937a9b5d0a35f850f14d307c00eaa39593d822 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 8 Oct 2025 21:43:11 +0500 Subject: [PATCH 5/5] add rseed validation --- mm2src/coins/z_coin.rs | 18 ++++++++++++++++++ .../tests/docker_tests/z_coin_docker_tests.rs | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 46ea75a36a..3e87e45147 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -771,6 +771,10 @@ impl ZCoin { .await .map_err(RawTransactionError::TransactionError)?; + if !validate_rseeds(&req.rseeds) { + return MmError::err(RawTransactionError::InvalidParam("invalid rseed".to_owned())); + } + for rseed in req.rseeds { self.z_fields .locked_notes_db @@ -2416,3 +2420,17 @@ fn rseed_to_string(rseed: &Rseed) -> String { Rseed::AfterZip212(rseed) => jubjub::Fr::from_bytes_wide(prf_expand(rseed, &INPUT).as_array()).to_string(), } } + +#[inline] +fn validate_rseeds(rseeds: &Vec) -> bool { + const MAX_RSEED_OR_RCM_LEN: usize = 64; + for rseed in rseeds { + if let Ok(v) = hex::decode(str_strip_0x!(rseed)) { + if v.len() <= MAX_RSEED_OR_RCM_LEN { + continue; + } + } + return false; + } + true +} diff --git a/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs index b53c0e011a..928e5bace8 100644 --- a/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs @@ -99,7 +99,7 @@ async fn zombie_coin_withdraw_and_send_maker_payment() { .expect("expected valid WithdrawRequest"), ) .await; - assert!(withdraw_res.is_ok()); + assert!(withdraw_res.is_ok(), "withdraw error {:?}", withdraw_res); let send_tx_res = coin .z_send_raw_tx( @@ -112,7 +112,7 @@ async fn zombie_coin_withdraw_and_send_maker_payment() { .expect("expected valid ZcoinSendRawTransactionRequest"), ) .await; - assert!(send_tx_res.is_ok()); + assert!(send_tx_res.is_ok(), "send tx error {:?}", send_tx_res); let time_lock = now_sec() - 3600; let secret_hash = [0; 20];