From 25fc41211f91322876830b3436ae25f79a1204a5 Mon Sep 17 00:00:00 2001 From: Kadan Stadelmann Date: Tue, 20 Aug 2024 01:45:14 +0200 Subject: [PATCH 01/15] docs(README): update commit badges to use dev branch (#2193) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff05f9d501..0d91d3cded 100755 --- a/README.md +++ b/README.md @@ -12,10 +12,10 @@ downloads - last commit + last commit - +
From 932669ae0494cb14264e3080b9b1d421b52559eb Mon Sep 17 00:00:00 2001 From: shamardy <39480341+shamardy@users.noreply.github.com> Date: Sat, 24 Aug 2024 03:41:19 +0300 Subject: [PATCH 02/15] fix(cors): allow OPTIONS request to KDF server (#2191) --- .github/workflows/test.yml | 2 +- mm2src/mm2_main/src/rpc.rs | 68 +++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 19cb9c5d67..a9790f9b13 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -213,7 +213,7 @@ jobs: - name: Test run: | - wget -O - https://raw.githubusercontent.com/KomodoPlatform/komodo/master/zcutil/fetch-params-alt.sh | bash + wget -O - https://raw.githubusercontent.com/KomodoPlatform/komodo/v0.8.1/zcutil/fetch-params-alt.sh | bash cargo test --test 'docker_tests_main' --features run-docker-tests --no-fail-fast wasm: diff --git a/mm2src/mm2_main/src/rpc.rs b/mm2src/mm2_main/src/rpc.rs index c7b483d952..2709d76f32 100644 --- a/mm2src/mm2_main/src/rpc.rs +++ b/mm2src/mm2_main/src/rpc.rs @@ -236,6 +236,8 @@ async fn process_single_request(ctx: MmArc, req: Json, client: SocketAddr) -> Re #[cfg(not(target_arch = "wasm32"))] async fn rpc_service(req: Request, ctx_h: u32, client: SocketAddr) -> Response { + const NON_ALLOWED_CHARS: &[char] = &['<', '>', '&']; + /// Unwraps a result or propagates its error 500 response with the specified headers (if they are present). macro_rules! try_sf { ($value: expr $(, $header_key:expr => $header_val:expr)*) => { @@ -269,39 +271,65 @@ async fn rpc_service(req: Request, ctx_h: u32, client: SocketAddr) -> Resp // https://github.com/artemii235/SuperNET/issues/219 let rpc_cors = match ctx.conf["rpccors"].as_str() { Some(s) => try_sf!(HeaderValue::from_str(s)), - None => HeaderValue::from_static("http://localhost:3000"), + None => { + if ctx.is_https() { + HeaderValue::from_static("https://localhost:3000") + } else { + HeaderValue::from_static("http://localhost:3000") + } + }, }; // Convert the native Hyper stream into a portable stream of `Bytes`. let (req, req_body) = req.into_parts(); - let req_bytes = try_sf!(hyper::body::to_bytes(req_body).await, ACCESS_CONTROL_ALLOW_ORIGIN => rpc_cors); - let req_str = String::from_utf8_lossy(req_bytes.as_ref()); - let is_invalid_input = req_str.chars().any(|c| c == '<' || c == '>' || c == '&'); - if is_invalid_input { + + if req.method == Method::OPTIONS { return Response::builder() - .status(500) - .header(CONTENT_TYPE, APPLICATION_JSON) - .body(Body::from(err_to_rpc_json_string("Invalid input"))) + .status(StatusCode::OK) + .header(ACCESS_CONTROL_ALLOW_ORIGIN, rpc_cors) + .header("Access-Control-Allow-Methods", "POST, OPTIONS") + .header("Access-Control-Allow-Headers", "Content-Type") + .header("Access-Control-Max-Age", "3600") + .body(Body::empty()) .unwrap(); } - let req_json: Json = try_sf!(json::from_slice(&req_bytes), ACCESS_CONTROL_ALLOW_ORIGIN => rpc_cors); - let res = try_sf!(process_rpc_request(ctx, req, req_json, client).await, ACCESS_CONTROL_ALLOW_ORIGIN => rpc_cors); - let (mut parts, body) = res.into_parts(); - parts.headers.insert(ACCESS_CONTROL_ALLOW_ORIGIN, rpc_cors); - let body_escaped = match std::str::from_utf8(&body) { - Ok(body_utf8) => { - let escaped = escape_answer(body_utf8); - escaped.as_bytes().to_vec() - }, - Err(_) => { + let req_json = { + let req_bytes = try_sf!(hyper::body::to_bytes(req_body).await, ACCESS_CONTROL_ALLOW_ORIGIN => rpc_cors); + let req_str = String::from_utf8_lossy(req_bytes.as_ref()); + let is_invalid_input = req_str.chars().any(|c| NON_ALLOWED_CHARS.contains(&c)); + if is_invalid_input { return Response::builder() .status(500) + .header(ACCESS_CONTROL_ALLOW_ORIGIN, rpc_cors) .header(CONTENT_TYPE, APPLICATION_JSON) - .body(Body::from(err_to_rpc_json_string("Non UTF-8 output"))) + .body(Body::from(err_to_rpc_json_string(&format!( + "Invalid input: contains one or more of the following non-allowed characters: {:?}", + NON_ALLOWED_CHARS + )))) .unwrap(); - }, + } + try_sf!(json::from_slice(&req_bytes), ACCESS_CONTROL_ALLOW_ORIGIN => rpc_cors) + }; + + let res = try_sf!(process_rpc_request(ctx, req, req_json, client).await, ACCESS_CONTROL_ALLOW_ORIGIN => rpc_cors); + let (mut parts, body) = res.into_parts(); + let body_escaped = { + let body_utf8 = match std::str::from_utf8(&body) { + Ok(body_utf8) => body_utf8, + Err(_) => { + return Response::builder() + .status(500) + .header(ACCESS_CONTROL_ALLOW_ORIGIN, rpc_cors) + .header(CONTENT_TYPE, APPLICATION_JSON) + .body(Body::from(err_to_rpc_json_string("Non UTF-8 output"))) + .unwrap(); + }, + }; + let escaped = escape_answer(body_utf8); + escaped.as_bytes().to_vec() }; + parts.headers.insert(ACCESS_CONTROL_ALLOW_ORIGIN, rpc_cors); Response::from_parts(parts, Body::from(body_escaped)) } From f6e83488049e579b61c9afcb58ce3d8a8bcec312 Mon Sep 17 00:00:00 2001 From: Alina Sharon <52405288+laruh@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:51:13 +0700 Subject: [PATCH 03/15] feat(eth-swap): eth tpu v2 methods, eth docker test enhancements (#2169) This commit implements EVM TPU taker methods and adds some enhancements for eth docker tests. --- mm2src/coins/coin_errors.rs | 20 +- mm2src/coins/eth.rs | 100 +- mm2src/coins/eth/eth_swap_v2.rs | 824 ++++++++++++- mm2src/coins/eth/nft_swap_v2/errors.rs | 40 +- mm2src/coins/eth/nft_swap_v2/mod.rs | 181 +-- mm2src/coins/eth/nft_swap_v2/structs.rs | 15 - mm2src/coins/eth/v2_activation.rs | 113 +- mm2src/coins/lp_coins.rs | 144 ++- mm2src/coins/qrc20.rs | 4 +- mm2src/coins/test_coin.rs | 14 +- mm2src/coins/utxo/qtum_delegation.rs | 6 +- mm2src/coins/utxo/utxo_common.rs | 21 +- mm2src/coins/utxo/utxo_standard.rs | 68 +- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 27 +- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 20 +- .../tests/docker_tests/docker_tests_common.rs | 114 +- .../tests/docker_tests/eth_docker_tests.rs | 1085 ++++++++++++++--- .../tests/docker_tests/swap_proto_v2_tests.rs | 52 +- .../contract_bytes/maker_swap_v2_bytes | 2 +- .../contract_bytes/nft_maker_swap_v2_bytes | 2 +- .../contract_bytes/nft_swap_contract_bytes | 1 - .../contract_bytes/taker_swap_v2_bytes | 2 +- mm2src/mm2_test_helpers/src/for_tests.rs | 36 +- mm2src/proxy_signature/src/lib.rs | 4 +- 24 files changed, 2217 insertions(+), 678 deletions(-) delete mode 100644 mm2src/mm2_test_helpers/contract_bytes/nft_swap_contract_bytes diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 34b0c46486..aead751eb0 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,4 +1,5 @@ -use crate::eth::nft_swap_v2::errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr, PrepareTxDataError}; +use crate::eth::eth_swap_v2::{PaymentStatusErr, ValidatePaymentV2Err}; +use crate::eth::nft_swap_v2::errors::{Erc721FunctionError, HtlcParamsError, PrepareTxDataError}; use crate::eth::{EthAssocTypesError, EthNftAssocTypesError, Web3RpcError}; use crate::{utxo::rpc_clients::UtxoRpcError, NumConversError, UnexpectedDerivationMethod}; use enum_derives::EnumFromStringify; @@ -50,6 +51,7 @@ pub enum ValidatePaymentError { TimelockOverflow(TryFromIntError), #[display(fmt = "Nft Protocol is not supported yet!")] NftProtocolNotSupported, + InvalidData(String), } impl From for ValidatePaymentError { @@ -84,9 +86,8 @@ impl From for ValidatePaymentError { fn from(err: PaymentStatusErr) -> Self { match err { PaymentStatusErr::Transport(e) => Self::Transport(e), - PaymentStatusErr::AbiError(e) - | PaymentStatusErr::Internal(e) - | PaymentStatusErr::TxDeserializationError(e) => Self::InternalError(e), + PaymentStatusErr::ABIError(e) | PaymentStatusErr::Internal(e) => Self::InternalError(e), + PaymentStatusErr::InvalidData(e) => Self::InvalidData(e), } } } @@ -95,7 +96,16 @@ impl From for ValidatePaymentError { fn from(err: HtlcParamsError) -> Self { match err { HtlcParamsError::WrongPaymentTx(e) => ValidatePaymentError::WrongPaymentTx(e), - HtlcParamsError::TxDeserializationError(e) => ValidatePaymentError::TxDeserializationError(e), + HtlcParamsError::ABIError(e) | HtlcParamsError::InvalidData(e) => ValidatePaymentError::InvalidData(e), + } + } +} + +impl From for ValidatePaymentError { + fn from(err: ValidatePaymentV2Err) -> Self { + match err { + ValidatePaymentV2Err::UnexpectedPaymentState(e) => ValidatePaymentError::UnexpectedPaymentState(e), + ValidatePaymentV2Err::WrongPaymentTx(e) => ValidatePaymentError::WrongPaymentTx(e), } } } diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 0d50f70024..a6cd170627 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -157,7 +157,7 @@ mod eip1559_gas_fee; pub(crate) use eip1559_gas_fee::FeePerGasEstimated; use eip1559_gas_fee::{BlocknativeGasApiCaller, FeePerGasSimpleEstimator, GasApiConfig, GasApiProvider, InfuraGasApiCaller}; -mod eth_swap_v2; +pub(crate) mod eth_swap_v2; /// https://github.com/artemii235/etomic-swap/blob/master/contracts/EtomicSwap.sol /// Dev chain (195.201.137.5:8565) contract address: 0x83965C539899cC0F918552e5A26915de40ee8852 @@ -827,9 +827,18 @@ impl EthCoinImpl { /// The id used to differentiate payments on Etomic swap smart contract pub(crate) fn etomic_swap_id(&self, time_lock: u32, secret_hash: &[u8]) -> Vec { let timelock_bytes = time_lock.to_le_bytes(); + self.generate_etomic_swap_id(&timelock_bytes, secret_hash) + } - let mut input = Vec::with_capacity(timelock_bytes.len() + secret_hash.len()); - input.extend_from_slice(&timelock_bytes); + /// The id used to differentiate payments on Etomic swap v2 smart contracts + pub(crate) fn etomic_swap_id_v2(&self, time_lock: u64, secret_hash: &[u8]) -> Vec { + let timelock_bytes = time_lock.to_le_bytes(); + self.generate_etomic_swap_id(&timelock_bytes, secret_hash) + } + + fn generate_etomic_swap_id(&self, time_lock_bytes: &[u8], secret_hash: &[u8]) -> Vec { + let mut input = Vec::with_capacity(time_lock_bytes.len() + secret_hash.len()); + input.extend_from_slice(time_lock_bytes); input.extend_from_slice(secret_hash); sha256(&input).to_vec() } @@ -7031,32 +7040,38 @@ impl Eip1559Ops for EthCoin { #[async_trait] impl TakerCoinSwapOpsV2 for EthCoin { + /// Wrapper for [EthCoin::send_taker_funding_impl] async fn send_taker_funding(&self, args: SendTakerFundingArgs<'_>) -> Result { self.send_taker_funding_impl(args).await } - async fn validate_taker_funding(&self, _args: ValidateTakerFundingArgs<'_, Self>) -> ValidateSwapV2TxResult { - todo!() + /// Wrapper for [EthCoin::validate_taker_funding_impl] + async fn validate_taker_funding(&self, args: ValidateTakerFundingArgs<'_, Self>) -> ValidateSwapV2TxResult { + self.validate_taker_funding_impl(args).await } - async fn refund_taker_funding_timelock(&self, _args: RefundPaymentArgs<'_>) -> Result { - todo!() + async fn refund_taker_funding_timelock( + &self, + args: RefundTakerPaymentArgs<'_>, + ) -> Result { + self.refund_taker_payment_with_timelock_impl(args).await } async fn refund_taker_funding_secret( &self, - _args: RefundFundingSecretArgs<'_, Self>, + args: RefundFundingSecretArgs<'_, Self>, ) -> Result { - todo!() + self.refund_taker_funding_secret_impl(args).await } + /// Wrapper for [EthCoin::search_for_taker_funding_spend_impl] async fn search_for_taker_funding_spend( &self, - _tx: &Self::Tx, + tx: &Self::Tx, _from_block: u64, _secret_hash: &[u8], ) -> Result>, SearchForFundingSpendErr> { - todo!() + self.search_for_taker_funding_spend_impl(tx).await } /// Eth doesnt have preimages @@ -7080,18 +7095,21 @@ impl TakerCoinSwapOpsV2 for EthCoin { Ok(()) } - /// Eth doesnt use multisig + /// Wrapper for [EthCoin::taker_payment_approve] async fn sign_and_send_taker_funding_spend( &self, _preimage: &TxPreimageWithSig, - _args: &GenTakerFundingSpendArgs<'_, Self>, + args: &GenTakerFundingSpendArgs<'_, Self>, _swap_unique_data: &[u8], ) -> Result { - todo!() + self.taker_payment_approve(args).await } - async fn refund_combined_taker_payment(&self, _args: RefundPaymentArgs<'_>) -> Result { - todo!() + async fn refund_combined_taker_payment( + &self, + args: RefundTakerPaymentArgs<'_>, + ) -> Result { + self.refund_taker_payment_with_timelock_impl(args).await } /// Eth doesnt have preimages @@ -7115,23 +7133,25 @@ impl TakerCoinSwapOpsV2 for EthCoin { Ok(()) } + /// Wrapper for [EthCoin::sign_and_broadcast_taker_payment_spend_impl] async fn sign_and_broadcast_taker_payment_spend( &self, _preimage: &TxPreimageWithSig, - _gen_args: &GenTakerPaymentSpendArgs<'_, Self>, - _secret: &[u8], + gen_args: &GenTakerPaymentSpendArgs<'_, Self>, + secret: &[u8], _swap_unique_data: &[u8], ) -> Result { - todo!() + self.sign_and_broadcast_taker_payment_spend_impl(gen_args, secret).await } + /// Wrapper for [EthCoin::wait_for_taker_payment_spend_impl] async fn wait_for_taker_payment_spend( &self, - _taker_payment: &Self::Tx, + taker_payment: &Self::Tx, _from_block: u64, - _wait_until: u64, + wait_until: u64, ) -> MmResult { - todo!() + self.wait_for_taker_payment_spend_impl(taker_payment, wait_until).await } } @@ -7162,3 +7182,39 @@ impl CommonSwapOpsV2 for EthCoin { self.derive_htlc_pubkey_v2(swap_unique_data).to_bytes() } } + +#[cfg(all(feature = "for-tests", not(target_arch = "wasm32")))] +impl EthCoin { + pub async fn set_coin_type(&self, new_coin_type: EthCoinType) -> EthCoin { + let coin = EthCoinImpl { + ticker: self.ticker.clone(), + coin_type: new_coin_type, + priv_key_policy: self.priv_key_policy.clone(), + derivation_method: Arc::clone(&self.derivation_method), + sign_message_prefix: self.sign_message_prefix.clone(), + swap_contract_address: self.swap_contract_address, + swap_v2_contracts: self.swap_v2_contracts, + fallback_swap_contract: self.fallback_swap_contract, + contract_supports_watchers: self.contract_supports_watchers, + web3_instances: AsyncMutex::new(self.web3_instances.lock().await.clone()), + decimals: self.decimals, + history_sync_state: Mutex::new(self.history_sync_state.lock().unwrap().clone()), + required_confirmations: AtomicU64::new( + self.required_confirmations.load(std::sync::atomic::Ordering::SeqCst), + ), + swap_txfee_policy: Mutex::new(self.swap_txfee_policy.lock().unwrap().clone()), + max_eth_tx_type: self.max_eth_tx_type, + ctx: self.ctx.clone(), + chain_id: self.chain_id, + trezor_coin: self.trezor_coin.clone(), + logs_block_range: self.logs_block_range, + address_nonce_locks: Arc::clone(&self.address_nonce_locks), + erc20_tokens_infos: Arc::clone(&self.erc20_tokens_infos), + nfts_infos: Arc::clone(&self.nfts_infos), + platform_fee_estimator_state: Arc::clone(&self.platform_fee_estimator_state), + gas_limit: EthGasLimit::default(), + abortable_system: self.abortable_system.create_subsystem().unwrap(), + }; + EthCoin(Arc::new(coin)) + } +} diff --git a/mm2src/coins/eth/eth_swap_v2.rs b/mm2src/coins/eth/eth_swap_v2.rs index 295fd7af2c..0d61ac6004 100644 --- a/mm2src/coins/eth/eth_swap_v2.rs +++ b/mm2src/coins/eth/eth_swap_v2.rs @@ -1,12 +1,30 @@ use super::eth::{wei_from_big_decimal, EthCoin, EthCoinType, SignedEthTx, TAKER_SWAP_V2}; -use super::{SendTakerFundingArgs, Transaction, TransactionErr}; +use super::{decode_contract_call, get_function_input_data, ParseCoinAssocTypes, RefundFundingSecretArgs, + RefundTakerPaymentArgs, SendTakerFundingArgs, SwapTxTypeWithSecretHash, TakerPaymentStateV2, Transaction, + TransactionErr, ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs}; +use crate::{FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, SearchForFundingSpendErr, + WaitForTakerPaymentSpendError}; +use common::executor::Timer; +use common::now_sec; use enum_derives::EnumFromStringify; -use ethabi::Token; +use ethabi::{Contract, Function, Token}; use ethcore_transaction::Action; use ethereum_types::{Address, Public, U256}; use ethkey::public_to_address; use futures::compat::Future01CompatExt; +use mm2_err_handle::prelude::{MapToMmResult, MmError, MmResult}; +use mm2_number::BigDecimal; use std::convert::TryInto; +use web3::types::{Transaction as Web3Tx, TransactionId}; + +/// ZERO_VALUE is used to represent a 0 amount in transactions where the value is encoded in the transaction input data. +/// This is typically used in function calls where the value is not directly transferred with the transaction, such as in +/// `spendTakerPayment` where the [amount](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L166) +/// is provided as part of the input data rather than as an Ether value +pub(crate) const ZERO_VALUE: u32 = 0; +const ETH_TAKER_PAYMENT: &str = "ethTakerPayment"; +const ERC20_TAKER_PAYMENT: &str = "erc20TakerPayment"; +const TAKER_PAYMENT_APPROVE: &str = "takerPaymentApprove"; struct TakerFundingArgs { dex_fee: U256, @@ -14,11 +32,24 @@ struct TakerFundingArgs { maker_address: Address, taker_secret_hash: [u8; 32], maker_secret_hash: [u8; 32], - funding_time_lock: u32, - payment_time_lock: u32, + funding_time_lock: u64, + payment_time_lock: u64, +} + +struct TakerRefundArgs { + dex_fee: U256, + payment_amount: U256, + maker_address: Address, + taker_secret: [u8; 32], + taker_secret_hash: [u8; 32], + maker_secret_hash: [u8; 32], + payment_time_lock: u64, + token_address: Address, } impl EthCoin { + /// Calls `"ethTakerPayment"` or `"erc20TakerPayment"` swap contract methods. + /// Returns taker sent payment transaction. pub(crate) async fn send_taker_funding_impl( &self, args: SendTakerFundingArgs<'_>, @@ -37,22 +68,22 @@ impl EthCoin { )); let funding_args = { let maker_address = public_to_address(&Public::from_slice(args.maker_pub)); - let funding_time_lock: u32 = try_tx_s!(args.funding_time_lock.try_into()); - let payment_time_lock: u32 = try_tx_s!(args.payment_time_lock.try_into()); TakerFundingArgs { dex_fee, payment_amount, maker_address, taker_secret_hash: try_tx_s!(args.taker_secret_hash.try_into()), maker_secret_hash: try_tx_s!(args.maker_secret_hash.try_into()), - funding_time_lock, - payment_time_lock, + funding_time_lock: args.funding_time_lock, + payment_time_lock: args.payment_time_lock, } }; match &self.coin_type { EthCoinType::Eth => { let data = try_tx_s!(self.prepare_taker_eth_funding_data(&funding_args).await); - let eth_total_payment = dex_fee + payment_amount; + let eth_total_payment = payment_amount.checked_add(dex_fee).ok_or_else(|| { + TransactionErr::Plain(ERRL!("Overflow occurred while calculating eth_total_payment")) + })?; self.sign_and_send_transaction( eth_total_payment, Action::Call(taker_swap_v2_contract), @@ -87,7 +118,7 @@ impl EthCoin { })?; } self.sign_and_send_transaction( - U256::from(0), + U256::from(ZERO_VALUE), Action::Call(taker_swap_v2_contract), data, // TODO need new consts and params for v2 calls. now it uses v1 @@ -96,15 +127,371 @@ impl EthCoin { .compat() .await }, - EthCoinType::Nft { .. } => Err(TransactionErr::ProtocolNotSupported( + EthCoinType::Nft { .. } => Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))), + } + } + + pub(crate) async fn validate_taker_funding_impl( + &self, + args: ValidateTakerFundingArgs<'_, Self>, + ) -> ValidateSwapV2TxResult { + if let EthCoinType::Nft { .. } = self.coin_type { + return MmError::err(ValidateSwapV2TxError::ProtocolNotSupported( "NFT protocol is not supported for ETH and ERC20 Swaps".to_string(), - )), + )); } + let taker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.taker_swap_v2_contract) + .ok_or_else(|| { + ValidateSwapV2TxError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) + })?; + validate_payment_args(args.taker_secret_hash, args.maker_secret_hash, &args.trading_amount) + .map_err(ValidateSwapV2TxError::Internal)?; + let taker_address = public_to_address(args.taker_pub); + let swap_id = self.etomic_swap_id_v2(args.payment_time_lock, args.maker_secret_hash); + let taker_status = self + .payment_status_v2( + taker_swap_v2_contract, + Token::FixedBytes(swap_id.clone()), + &TAKER_SWAP_V2, + EthPaymentType::TakerPayments, + 3, + ) + .await?; + + let tx_from_rpc = self.transaction(TransactionId::Hash(args.funding_tx.tx_hash())).await?; + let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| { + ValidateSwapV2TxError::TxDoesNotExist(format!( + "Didn't find provided tx {:?} on ETH node", + args.funding_tx.tx_hash() + )) + })?; + validate_from_to_and_status( + tx_from_rpc, + taker_address, + taker_swap_v2_contract, + taker_status, + TakerPaymentStateV2::PaymentSent as u8, + )?; + + let validation_args = { + let dex_fee = wei_from_big_decimal(&args.dex_fee.fee_amount().into(), self.decimals)?; + let payment_amount = wei_from_big_decimal(&(args.trading_amount + args.premium_amount), self.decimals)?; + TakerValidationArgs { + swap_id, + amount: payment_amount, + dex_fee, + receiver: self.my_addr().await, + taker_secret_hash: args.taker_secret_hash, + maker_secret_hash: args.maker_secret_hash, + funding_time_lock: args.funding_time_lock, + payment_time_lock: args.payment_time_lock, + } + }; + match self.coin_type { + EthCoinType::Eth => { + let function = TAKER_SWAP_V2.function(ETH_TAKER_PAYMENT)?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0)?; + validate_eth_taker_payment_data(&decoded, &validation_args, function, tx_from_rpc.value)?; + }, + EthCoinType::Erc20 { token_addr, .. } => { + let function = TAKER_SWAP_V2.function(ERC20_TAKER_PAYMENT)?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0)?; + validate_erc20_taker_payment_data(&decoded, &validation_args, function, token_addr)?; + }, + EthCoinType::Nft { .. } => unreachable!(), + } + Ok(()) } + /// Taker approves payment calling `takerPaymentApprove` for EVM based chains. + /// Function accepts taker payment transaction, returns taker approve payment transaction. + pub(crate) async fn taker_payment_approve( + &self, + args: &GenTakerFundingSpendArgs<'_, Self>, + ) -> Result { + // TODO need new consts and params for v2 calls, here should be common `gas_limit.taker_approve` param for Eth and Erc20 + let gas_limit = match self.coin_type { + EthCoinType::Eth | EthCoinType::Erc20 { .. } => U256::from(self.gas_limit.eth_payment), + EthCoinType::Nft { .. } => { + return Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))) + }, + }; + let (taker_swap_v2_contract, send_func, token_address) = self + .taker_swap_v2_details(ETH_TAKER_PAYMENT, ERC20_TAKER_PAYMENT) + .await?; + let decoded = try_tx_s!(decode_contract_call(send_func, args.funding_tx.unsigned().data())); + let taker_status = try_tx_s!( + self.payment_status_v2( + taker_swap_v2_contract, + decoded[0].clone(), + &TAKER_SWAP_V2, + EthPaymentType::TakerPayments, + 3, + ) + .await + ); + validate_payment_state(args.funding_tx, taker_status, TakerPaymentStateV2::PaymentSent as u8) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let data = try_tx_s!( + self.prepare_taker_payment_approve_data(args, decoded, token_address) + .await + ); + let approve_tx = self + .sign_and_send_transaction( + U256::from(ZERO_VALUE), + Action::Call(taker_swap_v2_contract), + data, + gas_limit, + ) + .compat() + .await?; + Ok(approve_tx) + } + + pub(crate) async fn refund_taker_payment_with_timelock_impl( + &self, + args: RefundTakerPaymentArgs<'_>, + ) -> Result { + let (token_address, gas_limit) = match &self.coin_type { + // TODO need new consts and params for v2 calls + EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), + EthCoinType::Erc20 { + platform: _, + token_addr, + } => (*token_addr, self.gas_limit.erc20_sender_refund), + EthCoinType::Nft { .. } => { + return Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))) + }, + }; + + let taker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.taker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + let dex_fee = try_tx_s!(wei_from_big_decimal( + &args.dex_fee.fee_amount().to_decimal(), + self.decimals + )); + let payment_amount = try_tx_s!(wei_from_big_decimal( + &(args.trading_amount + args.premium_amount), + self.decimals + )); + let maker_address = public_to_address(&Public::from_slice(args.maker_pub)); + let (maker_secret_hash, taker_secret_hash) = match args.tx_type_with_secret_hash { + SwapTxTypeWithSecretHash::TakerPaymentV2 { + maker_secret_hash, + taker_secret_hash, + } => (maker_secret_hash, taker_secret_hash), + _ => { + return Err(TransactionErr::Plain(ERRL!( + "Unsupported swap tx type for timelock refund" + ))) + }, + }; + + let args = TakerRefundArgs { + dex_fee, + payment_amount, + maker_address, + taker_secret: [0u8; 32], + taker_secret_hash: try_tx_s!(taker_secret_hash.try_into()), + maker_secret_hash: try_tx_s!(maker_secret_hash.try_into()), + payment_time_lock: args.time_lock, + token_address, + }; + let data = try_tx_s!(self.prepare_taker_refund_payment_timelock_data(args).await); + + self.sign_and_send_transaction( + U256::from(ZERO_VALUE), + Action::Call(taker_swap_v2_contract), + data, + U256::from(gas_limit), + ) + .compat() + .await + } + + pub(crate) async fn refund_taker_funding_secret_impl( + &self, + args: RefundFundingSecretArgs<'_, Self>, + ) -> Result { + let (token_address, gas_limit) = match &self.coin_type { + // TODO need new consts and params for v2 calls + EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), + EthCoinType::Erc20 { + platform: _, + token_addr, + } => (*token_addr, self.gas_limit.erc20_sender_refund), + EthCoinType::Nft { .. } => { + return Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))) + }, + }; + + let taker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.taker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + let taker_secret = try_tx_s!(args.taker_secret.try_into()); + let maker_secret_hash = try_tx_s!(args.maker_secret_hash.try_into()); + let dex_fee = try_tx_s!(wei_from_big_decimal( + &args.dex_fee.fee_amount().to_decimal(), + self.decimals + )); + let payment_amount = try_tx_s!(wei_from_big_decimal( + &(args.trading_amount + args.premium_amount), + self.decimals + )); + let maker_address = public_to_address(args.maker_pubkey); + + let refund_args = TakerRefundArgs { + dex_fee, + payment_amount, + maker_address, + taker_secret, + taker_secret_hash: [0u8; 32], + maker_secret_hash, + payment_time_lock: args.payment_time_lock, + token_address, + }; + let data = try_tx_s!(self.prepare_taker_refund_payment_secret_data(&refund_args).await); + + self.sign_and_send_transaction( + U256::from(ZERO_VALUE), + Action::Call(taker_swap_v2_contract), + data, + U256::from(gas_limit), + ) + .compat() + .await + } + + /// Checks that taker payment state is `TakerApproved`. + /// Accepts a taker-approved payment transaction and returns it if the state is correct. + pub(crate) async fn search_for_taker_funding_spend_impl( + &self, + tx: &SignedEthTx, + ) -> Result>, SearchForFundingSpendErr> { + let (decoded, taker_swap_v2_contract) = self + .get_decoded_and_swap_contract(tx, TAKER_PAYMENT_APPROVE) + .await + .map_err(|e| SearchForFundingSpendErr::Internal(ERRL!("{}", e)))?; + let taker_status = self + .payment_status_v2( + taker_swap_v2_contract, + decoded[0].clone(), // id from takerPaymentApprove + &TAKER_SWAP_V2, + EthPaymentType::TakerPayments, + 3, + ) + .await + .map_err(|e| SearchForFundingSpendErr::Internal(ERRL!("{}", e)))?; + if taker_status == U256::from(TakerPaymentStateV2::TakerApproved as u8) { + return Ok(Some(FundingTxSpend::TransferredToTakerPayment(tx.clone()))); + } + Ok(None) + } + + /// Taker swap contract `spendTakerPayment` method is called for EVM based chains. + /// Returns maker spent payment transaction. + pub(crate) async fn sign_and_broadcast_taker_payment_spend_impl( + &self, + gen_args: &GenTakerPaymentSpendArgs<'_, Self>, + secret: &[u8], + ) -> Result { + // TODO need new consts and params for v2 calls + let gas_limit = match self.coin_type { + EthCoinType::Eth => U256::from(self.gas_limit.eth_receiver_spend), + EthCoinType::Erc20 { .. } => U256::from(self.gas_limit.erc20_receiver_spend), + EthCoinType::Nft { .. } => { + return Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))) + }, + }; + let (taker_swap_v2_contract, approve_func, token_address) = self + .taker_swap_v2_details(TAKER_PAYMENT_APPROVE, TAKER_PAYMENT_APPROVE) + .await?; + let decoded = try_tx_s!(decode_contract_call(approve_func, gen_args.taker_tx.unsigned().data())); + let taker_status = try_tx_s!( + self.payment_status_v2( + taker_swap_v2_contract, + decoded[0].clone(), + &TAKER_SWAP_V2, + EthPaymentType::TakerPayments, + 3, + ) + .await + ); + validate_payment_state( + gen_args.taker_tx, + taker_status, + TakerPaymentStateV2::TakerApproved as u8, + ) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let data = try_tx_s!( + self.prepare_spend_taker_payment_data(gen_args, secret, decoded, token_address) + .await + ); + let spend_payment_tx = self + .sign_and_send_transaction( + U256::from(ZERO_VALUE), + Action::Call(taker_swap_v2_contract), + data, + gas_limit, + ) + .compat() + .await?; + Ok(spend_payment_tx) + } + + /// Checks that taker payment state is `MakerSpent`. + /// Accepts maker spent payment transaction and returns it if payment status is correct. + pub(crate) async fn wait_for_taker_payment_spend_impl( + &self, + taker_payment: &SignedEthTx, + wait_until: u64, + ) -> MmResult { + let (decoded, taker_swap_v2_contract) = self + .get_decoded_and_swap_contract(taker_payment, "spendTakerPayment") + .await?; + loop { + let taker_status = self + .payment_status_v2( + taker_swap_v2_contract, + decoded[0].clone(), // id from spendTakerPayment + &TAKER_SWAP_V2, + EthPaymentType::TakerPayments, + 3, + ) + .await?; + if taker_status == U256::from(TakerPaymentStateV2::MakerSpent as u8) { + return Ok(taker_payment.clone()); + } + let now = now_sec(); + if now > wait_until { + return MmError::err(WaitForTakerPaymentSpendError::Timeout { wait_until, now }); + } + Timer::sleep(10.).await; + } + } + + /// Prepares data for EtomicSwapTakerV2 contract [ethTakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L44) method async fn prepare_taker_eth_funding_data(&self, args: &TakerFundingArgs) -> Result, PrepareTxDataError> { - let function = TAKER_SWAP_V2.function("ethTakerPayment")?; - let id = self.etomic_swap_id(args.payment_time_lock, &args.maker_secret_hash); + let function = TAKER_SWAP_V2.function(ETH_TAKER_PAYMENT)?; + let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); let data = function.encode_input(&[ Token::FixedBytes(id), Token::Uint(args.dex_fee), @@ -117,18 +504,19 @@ impl EthCoin { Ok(data) } + /// Prepares data for EtomicSwapTakerV2 contract [erc20TakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L83) method async fn prepare_taker_erc20_funding_data( &self, args: &TakerFundingArgs, - token_addr: Address, + token_address: Address, ) -> Result, PrepareTxDataError> { - let function = TAKER_SWAP_V2.function("erc20TakerPayment")?; - let id = self.etomic_swap_id(args.payment_time_lock, &args.maker_secret_hash); + let function = TAKER_SWAP_V2.function(ERC20_TAKER_PAYMENT)?; + let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); let data = function.encode_input(&[ Token::FixedBytes(id), Token::Uint(args.payment_amount), Token::Uint(args.dex_fee), - Token::Address(token_addr), + Token::Address(token_address), Token::Address(args.maker_address), Token::FixedBytes(args.taker_secret_hash.to_vec()), Token::FixedBytes(args.maker_secret_hash.to_vec()), @@ -137,14 +525,406 @@ impl EthCoin { ])?; Ok(data) } + + /// Prepares data for EtomicSwapTakerV2 contract [refundTakerPaymentTimelock](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L208) method + async fn prepare_taker_refund_payment_timelock_data( + &self, + args: TakerRefundArgs, + ) -> Result, PrepareTxDataError> { + let function = TAKER_SWAP_V2.function("refundTakerPaymentTimelock")?; + let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); + let data = function.encode_input(&[ + Token::FixedBytes(id), + Token::Uint(args.payment_amount), + Token::Uint(args.dex_fee), + Token::Address(args.maker_address), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Address(args.token_address), + ])?; + Ok(data) + } + + /// Prepares data for EtomicSwapTakerV2 contract [refundTakerPaymentSecret](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L267) method + async fn prepare_taker_refund_payment_secret_data( + &self, + args: &TakerRefundArgs, + ) -> Result, PrepareTxDataError> { + let function = TAKER_SWAP_V2.function("refundTakerPaymentSecret")?; + let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); + let data = function.encode_input(&[ + Token::FixedBytes(id), + Token::Uint(args.payment_amount), + Token::Uint(args.dex_fee), + Token::Address(args.maker_address), + Token::FixedBytes(args.taker_secret.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Address(args.token_address), + ])?; + Ok(data) + } + + /// This function constructs the encoded transaction input data required to approve the taker payment ([takerPaymentApprove](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L128)). + /// The `decoded` parameter should contain the transaction input data from the `ethTakerPayment` or `erc20TakerPayment` function of the EtomicSwapTakerV2 contract. + async fn prepare_taker_payment_approve_data( + &self, + args: &GenTakerFundingSpendArgs<'_, Self>, + decoded: Vec, + token_address: Address, + ) -> Result, PrepareTxDataError> { + let function = TAKER_SWAP_V2.function(TAKER_PAYMENT_APPROVE)?; + let data = match self.coin_type { + EthCoinType::Eth => { + check_decoded_length(&decoded, 7)?; + let dex_fee = match &decoded[1] { + Token::Uint(value) => value, + _ => return Err(PrepareTxDataError::Internal("Invalid token type for dex fee".into())), + }; + let amount = args + .funding_tx + .unsigned() + .value() + .checked_sub(*dex_fee) + .ok_or_else(|| { + PrepareTxDataError::Internal("Underflow occurred while calculating amount".into()) + })?; + function.encode_input(&[ + decoded[0].clone(), // id from ethTakerPayment + Token::Uint(amount), // calculated payment amount (tx value - dexFee) + decoded[1].clone(), // dexFee from ethTakerPayment + decoded[2].clone(), // receiver from ethTakerPayment + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Address(token_address), // should be zero address Address::default() + ])? + }, + EthCoinType::Erc20 { .. } => { + check_decoded_length(&decoded, 9)?; + function.encode_input(&[ + decoded[0].clone(), // id from erc20TakerPayment + decoded[1].clone(), // amount from erc20TakerPayment + decoded[2].clone(), // dexFee from erc20TakerPayment + decoded[4].clone(), // receiver from erc20TakerPayment + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Address(token_address), // erc20 token address from EthCoinType::Erc20 + ])? + }, + EthCoinType::Nft { .. } => { + return Err(PrepareTxDataError::Internal("EthCoinType must be ETH or ERC20".into())) + }, + }; + Ok(data) + } + + /// Prepares data for EtomicSwapTakerV2 contract [spendTakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L164) method + async fn prepare_spend_taker_payment_data( + &self, + args: &GenTakerPaymentSpendArgs<'_, Self>, + secret: &[u8], + decoded: Vec, + token_address: Address, + ) -> Result, PrepareTxDataError> { + check_decoded_length(&decoded, 7)?; + let function = TAKER_SWAP_V2.function("spendTakerPayment")?; + let taker_address = public_to_address(args.taker_pub); + let data = function.encode_input(&[ + decoded[0].clone(), // id from takerPaymentApprove + decoded[1].clone(), // amount from takerPaymentApprove + decoded[2].clone(), // dexFee from takerPaymentApprove + Token::Address(taker_address), // taker address + decoded[4].clone(), // takerSecretHash from ethTakerPayment + Token::FixedBytes(secret.to_vec()), // makerSecret + Token::Address(token_address), // tokenAddress + ])?; + Ok(data) + } + + /// Retrieves the payment status from a given smart contract address based on the swap ID and state type. + pub(crate) async fn payment_status_v2( + &self, + swap_address: Address, + swap_id: Token, + contract_abi: &Contract, + payment_type: EthPaymentType, + state_index: usize, + ) -> Result { + let function_name = payment_type.as_str(); + let function = contract_abi.function(function_name)?; + let data = function.encode_input(&[swap_id])?; + let bytes = self + .call_request(self.my_addr().await, swap_address, None, Some(data.into())) + .await?; + let decoded_tokens = function.decode_output(&bytes.0)?; + + let state = decoded_tokens.get(state_index).ok_or_else(|| { + PaymentStatusErr::Internal(format!( + "Payment status must contain 'state' as the {} token", + state_index + )) + })?; + match state { + Token::Uint(state) => Ok(*state), + _ => Err(PaymentStatusErr::InvalidData(format!( + "Payment status must be Uint, got {:?}", + state + ))), + } + } + + /// Retrieves the taker smart contract address, the corresponding function, and the token address. + /// + /// Depending on the coin type (ETH or ERC20), it fetches the appropriate function name and token address. + /// Returns an error if the coin type is NFT or if the `swap_v2_contracts` is None. + async fn taker_swap_v2_details( + &self, + eth_func_name: &str, + erc20_func_name: &str, + ) -> Result<(Address, &Function, Address), TransactionErr> { + let (func, token_address) = match self.coin_type { + EthCoinType::Eth => (try_tx_s!(TAKER_SWAP_V2.function(eth_func_name)), Address::default()), + EthCoinType::Erc20 { token_addr, .. } => (try_tx_s!(TAKER_SWAP_V2.function(erc20_func_name)), token_addr), + EthCoinType::Nft { .. } => { + return Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))) + }, + }; + let taker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.taker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + Ok((taker_swap_v2_contract, func, token_address)) + } + + async fn get_decoded_and_swap_contract( + &self, + tx: &SignedEthTx, + function_name: &str, + ) -> Result<(Vec, Address), PrepareTxDataError> { + let decoded = { + let func = match self.coin_type { + EthCoinType::Eth | EthCoinType::Erc20 { .. } => TAKER_SWAP_V2.function(function_name)?, + EthCoinType::Nft { .. } => { + return Err(PrepareTxDataError::Internal( + "NFT protocol is not supported for ETH and ERC20 Swaps".to_string(), + )); + }, + }; + decode_contract_call(func, tx.unsigned().data())? + }; + let taker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.taker_swap_v2_contract) + .ok_or_else(|| { + PrepareTxDataError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) + })?; + + Ok((decoded, taker_swap_v2_contract)) + } +} + +#[derive(Debug, Display, EnumFromStringify)] +pub(crate) enum PrepareTxDataError { + #[from_stringify("ethabi::Error")] + #[display(fmt = "ABI error: {}", _0)] + ABIError(String), + #[display(fmt = "Internal error: {}", _0)] + Internal(String), +} + +// TODO validate premium when add its support in swap_v2 +fn validate_payment_args<'a>( + taker_secret_hash: &'a [u8], + maker_secret_hash: &'a [u8], + trading_amount: &BigDecimal, +) -> Result<(), String> { + if !is_positive(trading_amount) { + return Err("trading_amount must be a positive value".to_string()); + } + if taker_secret_hash.len() != 32 { + return Err("taker_secret_hash must be 32 bytes".to_string()); + } + if maker_secret_hash.len() != 32 { + return Err("maker_secret_hash must be 32 bytes".to_string()); + } + Ok(()) +} + +/// function to check if BigDecimal is a positive value +#[inline(always)] +fn is_positive(amount: &BigDecimal) -> bool { amount > &BigDecimal::from(0) } + +pub(crate) fn validate_from_to_and_status( + tx_from_rpc: &Web3Tx, + expected_from: Address, + expected_to: Address, + status: U256, + expected_status: u8, +) -> Result<(), MmError> { + if status != U256::from(expected_status) { + return MmError::err(ValidatePaymentV2Err::UnexpectedPaymentState(format!( + "Payment state is not `PaymentSent`, got {}", + status + ))); + } + if tx_from_rpc.from != Some(expected_from) { + return MmError::err(ValidatePaymentV2Err::WrongPaymentTx(format!( + "Payment tx {:?} was sent from wrong address, expected {:?}", + tx_from_rpc, expected_from + ))); + } + // (in NFT case) as NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address + if tx_from_rpc.to != Some(expected_to) { + return MmError::err(ValidatePaymentV2Err::WrongPaymentTx(format!( + "Payment tx {:?} was sent to wrong address, expected {:?}", + tx_from_rpc, expected_to, + ))); + } + Ok(()) +} + +struct TakerValidationArgs<'a> { + swap_id: Vec, + amount: U256, + dex_fee: U256, + receiver: Address, + taker_secret_hash: &'a [u8], + maker_secret_hash: &'a [u8], + funding_time_lock: u64, + payment_time_lock: u64, +} + +/// Validation function for ETH taker payment data +fn validate_eth_taker_payment_data( + decoded: &[Token], + args: &TakerValidationArgs, + func: &Function, + tx_value: U256, +) -> Result<(), MmError> { + let checks = vec![ + (0, Token::FixedBytes(args.swap_id.clone()), "id"), + (1, Token::Uint(args.dex_fee), "dexFee"), + (2, Token::Address(args.receiver), "receiver"), + (3, Token::FixedBytes(args.taker_secret_hash.to_vec()), "takerSecretHash"), + (4, Token::FixedBytes(args.maker_secret_hash.to_vec()), "makerSecretHash"), + (5, Token::Uint(U256::from(args.funding_time_lock)), "preApproveLockTime"), + (6, Token::Uint(U256::from(args.payment_time_lock)), "paymentLockTime"), + ]; + + for (index, expected_token, field_name) in checks { + let token = get_function_input_data(decoded, func, index).map_to_mm(ValidateSwapV2TxError::Internal)?; + if token != expected_token { + return MmError::err(ValidateSwapV2TxError::WrongPaymentTx(format!( + "ETH Taker Payment `{}` {:?} is invalid, expected {:?}", + field_name, + decoded.get(index), + expected_token + ))); + } + } + let total = args.amount.checked_add(args.dex_fee).ok_or_else(|| { + ValidateSwapV2TxError::Overflow("Overflow occurred while calculating total payment".to_string()) + })?; + if total != tx_value { + return MmError::err(ValidateSwapV2TxError::WrongPaymentTx(format!( + "ETH Taker Payment amount, is invalid, expected {:?}, got {:?}", + total, tx_value + ))); + } + Ok(()) +} + +/// Validation function for ERC20 taker payment data +fn validate_erc20_taker_payment_data( + decoded: &[Token], + args: &TakerValidationArgs, + func: &Function, + token_addr: Address, +) -> Result<(), MmError> { + let checks = vec![ + (0, Token::FixedBytes(args.swap_id.clone()), "id"), + (1, Token::Uint(args.amount), "amount"), + (2, Token::Uint(args.dex_fee), "dexFee"), + (3, Token::Address(token_addr), "tokenAddress"), + (4, Token::Address(args.receiver), "receiver"), + (5, Token::FixedBytes(args.taker_secret_hash.to_vec()), "takerSecretHash"), + (6, Token::FixedBytes(args.maker_secret_hash.to_vec()), "makerSecretHash"), + (7, Token::Uint(U256::from(args.funding_time_lock)), "preApproveLockTime"), + (8, Token::Uint(U256::from(args.payment_time_lock)), "paymentLockTime"), + ]; + + for (index, expected_token, field_name) in checks { + let token = get_function_input_data(decoded, func, index).map_to_mm(ValidateSwapV2TxError::Internal)?; + if token != expected_token { + return MmError::err(ValidateSwapV2TxError::WrongPaymentTx(format!( + "ERC20 Taker Payment `{}` {:?} is invalid, expected {:?}", + field_name, + decoded.get(index), + expected_token + ))); + } + } + Ok(()) +} + +pub(crate) fn validate_payment_state( + tx: &SignedEthTx, + state: U256, + expected_state: u8, +) -> Result<(), PrepareTxDataError> { + if state != U256::from(expected_state) { + return Err(PrepareTxDataError::Internal(format!( + "Payment {:?} state is not `{}`, got `{}`", + tx, expected_state, state + ))); + } + Ok(()) +} + +#[derive(Debug, Display)] +pub(crate) enum ValidatePaymentV2Err { + UnexpectedPaymentState(String), + WrongPaymentTx(String), +} + +pub(crate) enum EthPaymentType { + MakerPayments, + TakerPayments, +} + +impl EthPaymentType { + pub(crate) fn as_str(&self) -> &'static str { + match self { + EthPaymentType::MakerPayments => "makerPayments", + EthPaymentType::TakerPayments => "takerPayments", + } + } } -#[allow(dead_code)] #[derive(Debug, Display, EnumFromStringify)] -enum PrepareTxDataError { +pub(crate) enum PaymentStatusErr { #[from_stringify("ethabi::Error")] - #[display(fmt = "Abi error: {}", _0)] - AbiError(String), + #[display(fmt = "ABI error: {}", _0)] + ABIError(String), + #[from_stringify("web3::Error")] + #[display(fmt = "Transport error: {}", _0)] + Transport(String), #[display(fmt = "Internal error: {}", _0)] Internal(String), + #[display(fmt = "Invalid data error: {}", _0)] + InvalidData(String), +} + +fn check_decoded_length(decoded: &Vec, expected_len: usize) -> Result<(), PrepareTxDataError> { + if decoded.len() != expected_len { + return Err(PrepareTxDataError::Internal(format!( + "Invalid number of tokens in decoded. Expected {}, found {}", + expected_len, + decoded.len() + ))); + } + Ok(()) } diff --git a/mm2src/coins/eth/nft_swap_v2/errors.rs b/mm2src/coins/eth/nft_swap_v2/errors.rs index e66cd437d0..02cb3c7626 100644 --- a/mm2src/coins/eth/nft_swap_v2/errors.rs +++ b/mm2src/coins/eth/nft_swap_v2/errors.rs @@ -1,41 +1,27 @@ +pub(crate) use crate::eth::eth_swap_v2::PrepareTxDataError; use enum_derives::EnumFromStringify; #[derive(Debug, Display)] pub(crate) enum Erc721FunctionError { - AbiError(String), + #[display(fmt = "ABI error: {}", _0)] + ABIError(String), FunctionNotFound(String), } -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub(crate) enum HtlcParamsError { WrongPaymentTx(String), - TxDeserializationError(String), -} - -#[derive(Debug, Display, EnumFromStringify)] -pub(crate) enum PaymentStatusErr { - #[from_stringify("ethabi::Error")] - #[display(fmt = "Abi error: {}", _0)] - AbiError(String), - #[from_stringify("web3::Error")] - #[display(fmt = "Transport error: {}", _0)] - Transport(String), - #[display(fmt = "Internal error: {}", _0)] - Internal(String), - #[display(fmt = "Tx deserialization error: {}", _0)] - TxDeserializationError(String), -} - -#[derive(Debug, Display, EnumFromStringify)] -pub(crate) enum PrepareTxDataError { #[from_stringify("ethabi::Error")] - #[display(fmt = "Abi error: {}", _0)] - AbiError(String), - #[display(fmt = "Internal error: {}", _0)] - Internal(String), - Erc721FunctionError(Erc721FunctionError), + #[display(fmt = "ABI error: {}", _0)] + ABIError(String), + InvalidData(String), } impl From for PrepareTxDataError { - fn from(e: Erc721FunctionError) -> Self { Self::Erc721FunctionError(e) } + fn from(e: Erc721FunctionError) -> Self { + match e { + Erc721FunctionError::ABIError(e) => PrepareTxDataError::ABIError(e), + Erc721FunctionError::FunctionNotFound(e) => PrepareTxDataError::Internal(e), + } + } } diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 52bff94978..d5de6dcc86 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -6,15 +6,16 @@ use ethkey::public_to_address; use futures::compat::Future01CompatExt; use mm2_err_handle::prelude::{MapToMmResult, MmError, MmResult}; use mm2_number::BigDecimal; -use std::convert::TryInto; -use web3::types::{Transaction as Web3Tx, TransactionId}; +use web3::types::TransactionId; pub(crate) mod errors; -use errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr, PrepareTxDataError}; +use errors::{Erc721FunctionError, HtlcParamsError, PrepareTxDataError}; mod structs; -use structs::{ExpectedHtlcParams, PaymentType, ValidationParams}; +use structs::{ExpectedHtlcParams, ValidationParams}; use super::ContractType; +use crate::eth::eth_swap_v2::{validate_from_to_and_status, validate_payment_state, EthPaymentType, PaymentStatusErr, + ZERO_VALUE}; use crate::eth::{decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, ERC1155_CONTRACT, ERC721_CONTRACT, NFT_MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundNftMakerPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, @@ -37,7 +38,7 @@ impl EthCoin { let data = try_tx_s!(self.prepare_nft_maker_payment_v2_data(&args, htlc_data).await); self.sign_and_send_transaction( - 0.into(), + ZERO_VALUE.into(), Action::Call(*args.nft_swap_info.token_address), data, U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value @@ -45,9 +46,9 @@ impl EthCoin { .compat() .await }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( - "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), - )), + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported(ERRL!( + "ETH and ERC20 protocols are not supported for NFT swaps." + ))), } } @@ -65,20 +66,18 @@ impl EthCoin { contract_type, ) .map_err(ValidatePaymentError::InternalError)?; + // TODO use swap contract address from self let etomic_swap_contract = args.nft_swap_info.swap_contract_address; let token_address = args.nft_swap_info.token_address; let maker_address = public_to_address(args.maker_pub); - let time_lock_u32 = args - .time_lock - .try_into() - .map_err(ValidatePaymentError::TimelockOverflow)?; - let swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + let swap_id = self.etomic_swap_id_v2(args.time_lock, args.maker_secret_hash); let maker_status = self .payment_status_v2( *etomic_swap_contract, Token::FixedBytes(swap_id.clone()), &NFT_MAKER_SWAP_V2, - PaymentType::MakerPayments, + EthPaymentType::MakerPayments, + 2, ) .await?; let tx_from_rpc = self @@ -90,7 +89,13 @@ impl EthCoin { args.maker_payment_tx.tx_hash() )) })?; - validate_from_to_and_maker_status(tx_from_rpc, maker_address, *token_address, maker_status).await?; + validate_from_to_and_status( + tx_from_rpc, + maker_address, + *token_address, + maker_status, + MakerPaymentStateV2::PaymentSent as u8, + )?; let (decoded, bytes_index) = get_decoded_tx_data_and_bytes_index(contract_type, &tx_from_rpc.input.0)?; @@ -149,13 +154,14 @@ impl EthCoin { &NFT_MAKER_SWAP_V2, &decoded, bytes_index, - PaymentType::MakerPayments, + EthPaymentType::MakerPayments, + 2 ) .await ); let data = try_tx_s!(self.prepare_spend_nft_maker_v2_data(&args, decoded, htlc_params, state)); self.sign_and_send_transaction( - 0.into(), + ZERO_VALUE.into(), Action::Call(*etomic_swap_contract), data, U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value @@ -163,9 +169,9 @@ impl EthCoin { .compat() .await }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( - "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), - )), + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported(ERRL!( + "ETH and ERC20 protocols are not supported for NFT swaps." + ))), } } @@ -187,14 +193,15 @@ impl EthCoin { &NFT_MAKER_SWAP_V2, &decoded, bytes_index, - PaymentType::MakerPayments, + EthPaymentType::MakerPayments, + 2 ) .await ); let data = try_tx_s!(self.prepare_refund_nft_maker_payment_v2_timelock(&args, decoded, htlc_params, state)); self.sign_and_send_transaction( - 0.into(), + ZERO_VALUE.into(), Action::Call(*etomic_swap_contract), data, U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value @@ -202,9 +209,9 @@ impl EthCoin { .compat() .await }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( - "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), - )), + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported(ERRL!( + "ETH and ERC20 protocols are not supported for NFT swaps." + ))), } } @@ -226,7 +233,8 @@ impl EthCoin { &NFT_MAKER_SWAP_V2, &decoded, bytes_index, - PaymentType::MakerPayments, + EthPaymentType::MakerPayments, + 2 ) .await ); @@ -234,7 +242,7 @@ impl EthCoin { let data = try_tx_s!(self.prepare_refund_nft_maker_payment_v2_secret(&args, decoded, htlc_params, state)); self.sign_and_send_transaction( - 0.into(), + ZERO_VALUE.into(), Action::Call(*etomic_swap_contract), data, U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value @@ -242,9 +250,9 @@ impl EthCoin { .compat() .await }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( - "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), - )), + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported(ERRL!( + "ETH and ERC20 protocols are not supported for NFT swaps." + ))), } } @@ -282,50 +290,18 @@ impl EthCoin { fn prepare_htlc_data(&self, args: &SendNftMakerPaymentArgs<'_, Self>) -> Result, PrepareTxDataError> { let taker_address = public_to_address(args.taker_pub); - let time_lock_u32 = args - .time_lock - .try_into() - .map_err(|e| PrepareTxDataError::Internal(ERRL!("{}", e)))?; - let id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + let id = self.etomic_swap_id_v2(args.time_lock, args.maker_secret_hash); let encoded = ethabi::encode(&[ Token::FixedBytes(id), Token::Address(taker_address), Token::Address(*args.nft_swap_info.token_address), Token::FixedBytes(args.taker_secret_hash.to_vec()), Token::FixedBytes(args.maker_secret_hash.to_vec()), - Token::Uint(U256::from(time_lock_u32)), + Token::Uint(U256::from(args.time_lock)), ]); Ok(encoded) } - /// Retrieves the payment status from a given smart contract address based on the swap ID and state type. - async fn payment_status_v2( - &self, - swap_address: Address, - swap_id: Token, - contract_abi: &Contract, - state_type: PaymentType, - ) -> Result { - let function_name = state_type.as_str(); - let function = contract_abi.function(function_name)?; - let data = function.encode_input(&[swap_id])?; - let bytes = self - .call_request(self.my_addr().await, swap_address, None, Some(data.into())) - .await?; - let decoded_tokens = function.decode_output(&bytes.0)?; - - let state = decoded_tokens - .get(2) - .ok_or_else(|| PaymentStatusErr::Internal(ERRL!("Payment status must contain 'state' as the 2nd token")))?; - match state { - Token::Uint(state) => Ok(*state), - _ => Err(PaymentStatusErr::Internal(ERRL!( - "Payment status must be Uint, got {:?}", - state - ))), - } - } - /// Prepares the encoded transaction data for spending a maker's NFT payment on the blockchain. /// /// This function selects the appropriate contract function based on the NFT's contract type (ERC1155 or ERC721) @@ -428,28 +404,30 @@ impl EthCoin { contract_abi: &Contract, decoded_data: &[Token], index: usize, - state_type: PaymentType, + payment_type: EthPaymentType, + state_index: usize, ) -> Result<(U256, Vec), PaymentStatusErr> { let data_bytes = match decoded_data.get(index) { Some(Token::Bytes(data_bytes)) => data_bytes, _ => { - return Err(PaymentStatusErr::TxDeserializationError(ERRL!( + return Err(PaymentStatusErr::InvalidData(ERRL!( "Failed to decode HTLCParams from data_bytes" ))) }, }; - let htlc_params = match ethabi::decode(htlc_params(), data_bytes) { - Ok(htlc_params) => htlc_params, - Err(_) => { - return Err(PaymentStatusErr::TxDeserializationError(ERRL!( - "Failed to decode HTLCParams from data_bytes" - ))) - }, - }; + let htlc_params = + ethabi::decode(htlc_params(), data_bytes).map_err(|e| PaymentStatusErr::ABIError(ERRL!("{}", e)))?; let state = self - .payment_status_v2(swap_address, htlc_params[0].clone(), contract_abi, state_type) + .payment_status_v2( + swap_address, + // swap_id has 0 index + htlc_params[0].clone(), + contract_abi, + payment_type, + state_index, + ) .await?; Ok((state, htlc_params)) @@ -495,20 +473,13 @@ fn decode_and_validate_htlc_params( let data_bytes = match decoded.get(index) { Some(Token::Bytes(bytes)) => bytes, _ => { - return MmError::err(HtlcParamsError::TxDeserializationError( + return MmError::err(HtlcParamsError::InvalidData( "Expected Bytes for HTLCParams data".to_string(), )) }, }; - let decoded_params = match ethabi::decode(htlc_params(), data_bytes) { - Ok(params) => params, - Err(_) => { - return MmError::err(HtlcParamsError::TxDeserializationError( - "Failed to decode HTLCParams from data_bytes".to_string(), - )) - }, - }; + let decoded_params = ethabi::decode(htlc_params(), data_bytes)?; let expected_taker_secret_hash = Token::FixedBytes(expected_params.taker_secret_hash.clone()); let expected_maker_secret_hash = Token::FixedBytes(expected_params.maker_secret_hash.clone()); @@ -587,34 +558,6 @@ fn validate_payment_args<'a>( Ok(()) } -async fn validate_from_to_and_maker_status( - tx_from_rpc: &Web3Tx, - expected_from: Address, - expected_to: Address, - maker_status: U256, -) -> ValidatePaymentResult<()> { - if maker_status != U256::from(MakerPaymentStateV2::PaymentSent as u8) { - return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( - "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", - maker_status - ))); - } - if tx_from_rpc.from != Some(expected_from) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment tx {:?} was sent from wrong address, expected {:?}", - tx_from_rpc, expected_from - ))); - } - // As NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address - if tx_from_rpc.to != Some(expected_to) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", - tx_from_rpc, expected_to, - ))); - } - Ok(()) -} - /// Identifies the correct `"safeTransferFrom"` function based on the contract type (either ERC1155 or ERC721) /// and decodes the provided contract call bytes using the ABI of the identified function. Additionally, it returns /// the index position of the "bytes" field within the function's parameters. @@ -637,7 +580,7 @@ pub(crate) fn get_decoded_tx_data_and_bytes_index( fn erc721_transfer_with_data<'a>() -> Result<&'a ethabi::Function, Erc721FunctionError> { let functions = ERC721_CONTRACT .functions_by_name("safeTransferFrom") - .map_err(|e| Erc721FunctionError::AbiError(ERRL!("{}", e)))?; + .map_err(|e| Erc721FunctionError::ABIError(ERRL!("{}", e)))?; // Find the correct function variant by inspecting the input parameters. let function = functions @@ -656,15 +599,3 @@ fn erc721_transfer_with_data<'a>() -> Result<&'a ethabi::Function, Erc721Functio })?; Ok(function) } - -fn validate_payment_state(tx: &SignedEthTx, state: U256, expected_state: u8) -> Result<(), PrepareTxDataError> { - if state != U256::from(expected_state) { - return Err(PrepareTxDataError::Internal(ERRL!( - "Payment {:?} state is not {}, got {}", - tx, - expected_state, - state - ))); - } - Ok(()) -} diff --git a/mm2src/coins/eth/nft_swap_v2/structs.rs b/mm2src/coins/eth/nft_swap_v2/structs.rs index a0c129bf4b..2866d81a01 100644 --- a/mm2src/coins/eth/nft_swap_v2/structs.rs +++ b/mm2src/coins/eth/nft_swap_v2/structs.rs @@ -16,18 +16,3 @@ pub(crate) struct ValidationParams<'a> { // Optional, as it's not needed for ERC721 pub(crate) amount: Option, } - -#[allow(dead_code)] -pub(crate) enum PaymentType { - MakerPayments, - TakerPayments, -} - -impl PaymentType { - pub(crate) fn as_str(&self) -> &'static str { - match self { - PaymentType::MakerPayments => "makerPayments", - PaymentType::TakerPayments => "takerPayments", - } - } -} diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index dffa0a4e17..15af41b3c2 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -541,7 +541,7 @@ impl EthCoin { } /// Activate eth coin from coin config and private key build policy, -/// version 2 of the activation function, with no intrinsic tokens creation +/// version 2 of the activation function, with no intrinsic tokens creation. pub async fn eth_coin_from_conf_and_request_v2( ctx: &MmArc, ticker: &str, @@ -796,7 +796,6 @@ async fn build_web3_instances( let event_handlers = rpc_event_handlers_for_eth_transport(ctx, coin_ticker.clone()); - let p2p_ctx = P2PContext::fetch_from_mm_arc(ctx); let mut web3_instances = Vec::with_capacity(eth_nodes.len()); for eth_node in eth_nodes { let uri: Uri = eth_node @@ -804,51 +803,7 @@ async fn build_web3_instances( .parse() .map_err(|_| EthActivationV2Error::InvalidPayload(format!("{} could not be parsed.", eth_node.url)))?; - let transport = match uri.scheme_str() { - Some("ws") | Some("wss") => { - const TMP_SOCKET_CONNECTION: Duration = Duration::from_secs(20); - - let node = WebsocketTransportNode { uri: uri.clone() }; - - let mut websocket_transport = WebsocketTransport::with_event_handlers(node, event_handlers.clone()); - - if eth_node.komodo_proxy { - websocket_transport.proxy_sign_keypair = Some(p2p_ctx.keypair().clone()); - } - - // Temporarily start the connection loop (we close the connection once we have the client version below). - // Ideally, it would be much better to not do this workaround, which requires a lot of refactoring or - // dropping websocket support on parity nodes. - let fut = websocket_transport - .clone() - .start_connection_loop(Some(Instant::now() + TMP_SOCKET_CONNECTION)); - let settings = AbortSettings::info_on_abort(format!("connection loop stopped for {:?}", uri)); - ctx.spawner().spawn_with_settings(fut, settings); - - Web3Transport::Websocket(websocket_transport) - }, - Some("http") | Some("https") => { - let node = HttpTransportNode { - uri, - komodo_proxy: eth_node.komodo_proxy, - }; - - let komodo_proxy = node.komodo_proxy; - let mut http_transport = HttpTransport::with_event_handlers(node, event_handlers.clone()); - - if komodo_proxy { - http_transport.proxy_sign_keypair = Some(p2p_ctx.keypair().clone()); - } - - Web3Transport::from(http_transport) - }, - _ => { - return MmError::err(EthActivationV2Error::InvalidPayload(format!( - "Invalid node address '{uri}'. Only http(s) and ws(s) nodes are supported" - ))); - }, - }; - + let transport = create_transport(ctx, &uri, ð_node, &event_handlers)?; let web3 = Web3::new(transport); let version = match web3.web3().client_version().await { Ok(v) => v, @@ -873,6 +828,70 @@ async fn build_web3_instances( Ok(web3_instances) } +fn create_transport( + ctx: &MmArc, + uri: &Uri, + eth_node: &EthNode, + event_handlers: &[RpcTransportEventHandlerShared], +) -> MmResult { + match uri.scheme_str() { + Some("ws") | Some("wss") => Ok(create_websocket_transport(ctx, uri, eth_node, event_handlers)), + Some("http") | Some("https") => Ok(create_http_transport(ctx, uri, eth_node, event_handlers)), + _ => MmError::err(EthActivationV2Error::InvalidPayload(format!( + "Invalid node address '{uri}'. Only http(s) and ws(s) nodes are supported" + ))), + } +} + +fn create_websocket_transport( + ctx: &MmArc, + uri: &Uri, + eth_node: &EthNode, + event_handlers: &[RpcTransportEventHandlerShared], +) -> Web3Transport { + const TMP_SOCKET_CONNECTION: Duration = Duration::from_secs(20); + + let node = WebsocketTransportNode { uri: uri.clone() }; + + let mut websocket_transport = WebsocketTransport::with_event_handlers(node, event_handlers.to_owned()); + + if eth_node.komodo_proxy { + websocket_transport.proxy_sign_keypair = Some(P2PContext::fetch_from_mm_arc(ctx).keypair().clone()); + } + + // Temporarily start the connection loop (we close the connection once we have the client version below). + // Ideally, it would be much better to not do this workaround, which requires a lot of refactoring or + // dropping websocket support on parity nodes. + let fut = websocket_transport + .clone() + .start_connection_loop(Some(Instant::now() + TMP_SOCKET_CONNECTION)); + let settings = AbortSettings::info_on_abort(format!("connection loop stopped for {:?}", uri)); + ctx.spawner().spawn_with_settings(fut, settings); + + Web3Transport::Websocket(websocket_transport) +} + +fn create_http_transport( + ctx: &MmArc, + uri: &Uri, + eth_node: &EthNode, + event_handlers: &[RpcTransportEventHandlerShared], +) -> Web3Transport { + let node = HttpTransportNode { + uri: uri.clone(), + komodo_proxy: eth_node.komodo_proxy, + }; + + let komodo_proxy = node.komodo_proxy; + let mut http_transport = HttpTransport::with_event_handlers(node, event_handlers.to_owned()); + + if komodo_proxy { + http_transport.proxy_sign_keypair = Some(P2PContext::fetch_from_mm_arc(ctx).keypair().clone()); + } + + Web3Transport::from(http_transport) +} + #[cfg(target_arch = "wasm32")] async fn build_metamask_transport( ctx: &MmArc, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 4e5d281b33..8ca714a34f 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -240,6 +240,7 @@ use coin_errors::{MyAddressError, ValidatePaymentError, ValidatePaymentFut, Vali pub mod coins_tests; pub mod eth; +use eth::eth_swap_v2::{PaymentStatusErr, ValidatePaymentV2Err}; use eth::GetValidEthWithdrawAddError; use eth::{eth_coin_from_conf_and_request, get_eth_address, EthCoin, EthGasDetailsErr, EthTxFeeDetails, GetEthAddressError, SignedEthTx}; @@ -319,6 +320,7 @@ pub mod z_coin; use crate::coin_balance::{BalanceObjectOps, HDWalletBalanceObject}; use z_coin::{ZCoin, ZcoinProtocolInfo}; #[cfg(feature = "enable-sia")] pub mod sia; +use crate::eth::eth_swap_v2::PrepareTxDataError; #[cfg(feature = "enable-sia")] use sia::SiaCoin; pub type TransactionFut = Box + Send>; @@ -885,7 +887,10 @@ pub enum SwapTxTypeWithSecretHash<'a> { taker_secret_hash: &'a [u8], }, /// Taker payment v2 - TakerPaymentV2 { maker_secret_hash: &'a [u8] }, + TakerPaymentV2 { + maker_secret_hash: &'a [u8], + taker_secret_hash: &'a [u8], + }, } impl<'a> SwapTxTypeWithSecretHash<'a> { @@ -907,7 +912,7 @@ impl<'a> SwapTxTypeWithSecretHash<'a> { my_public, other_public, ), - SwapTxTypeWithSecretHash::TakerPaymentV2 { maker_secret_hash } => { + SwapTxTypeWithSecretHash::TakerPaymentV2 { maker_secret_hash, .. } => { swap_proto_v2_scripts::taker_payment_script(time_lock, maker_secret_hash, my_public, other_public) }, } @@ -921,7 +926,7 @@ impl<'a> SwapTxTypeWithSecretHash<'a> { maker_secret_hash, taker_secret_hash, } => [*maker_secret_hash, *taker_secret_hash].concat(), - SwapTxTypeWithSecretHash::TakerPaymentV2 { maker_secret_hash } => maker_secret_hash.to_vec(), + SwapTxTypeWithSecretHash::TakerPaymentV2 { maker_secret_hash, .. } => maker_secret_hash.to_vec(), } } } @@ -985,6 +990,32 @@ pub struct RefundPaymentArgs<'a> { pub watcher_reward: bool, } +#[derive(Debug)] +pub struct RefundMakerPaymentTimelockArgs<'a> { + pub payment_tx: &'a [u8], + pub time_lock: u64, + pub taker_pub: &'a [u8], + pub tx_type_with_secret_hash: SwapTxTypeWithSecretHash<'a>, + pub swap_contract_address: &'a Option, + pub swap_unique_data: &'a [u8], + pub watcher_reward: bool, +} + +#[derive(Debug)] +pub struct RefundTakerPaymentArgs<'a> { + pub payment_tx: &'a [u8], + pub time_lock: u64, + pub maker_pub: &'a [u8], + pub tx_type_with_secret_hash: SwapTxTypeWithSecretHash<'a>, + pub swap_unique_data: &'a [u8], + pub watcher_reward: bool, + pub dex_fee: &'a DexFee, + /// Additional reward for maker (premium) + pub premium_amount: BigDecimal, + /// Actual volume of taker's payment + pub trading_amount: BigDecimal, +} + /// Helper struct wrapping arguments for [SwapOps::check_if_my_payment_sent]. #[derive(Clone, Debug)] pub struct CheckIfMyPaymentSentArgs<'a> { @@ -1310,8 +1341,6 @@ pub struct RefundFundingSecretArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { pub taker_secret: &'a [u8], pub taker_secret_hash: &'a [u8], pub maker_secret_hash: &'a [u8], - pub swap_contract_address: &'a Option, - /// DEX fee pub dex_fee: &'a DexFee, /// Additional reward for maker (premium) pub premium_amount: BigDecimal, @@ -1343,12 +1372,18 @@ pub struct GenTakerFundingSpendArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { pub struct ValidateTakerFundingArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Taker funding transaction pub funding_tx: &'a Coin::Tx, - /// Taker will be able to refund the payment after this timestamp - pub time_lock: u64, + /// In EVM case: The timestamp after which the taker can refund the funding transaction if the taker hasn't pre-approved the transaction + /// In UTXO case: Taker will be able to refund the payment after this timestamp + pub funding_time_lock: u64, + /// In EVM case: The timestamp after which the taker can refund the payment transaction if the maker hasn't claimed it by revealing their secret. + /// UTXO doesn't use it + pub payment_time_lock: u64, /// The hash of the secret generated by taker pub taker_secret_hash: &'a [u8], + /// The hash of the secret generated by maker + pub maker_secret_hash: &'a [u8], /// Taker's pubkey - pub other_pub: &'a Coin::Pubkey, + pub taker_pub: &'a Coin::Pubkey, /// DEX fee amount pub dex_fee: &'a DexFee, /// Additional reward for maker (premium) @@ -1429,23 +1464,36 @@ impl From for TxGenError { } /// Enum covering error cases that can happen during swap v2 transaction validation. -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum ValidateSwapV2TxError { /// Payment sent to wrong address or has invalid amount. InvalidDestinationOrAmount(String), /// Error during conversion of BigDecimal amount to coin's specific monetary units (satoshis, wei, etc.). NumConversion(String), /// RPC error. + #[from_stringify("web3::Error")] Rpc(String), /// Serialized tx bytes don't match ones received from coin's RPC. #[display(fmt = "Tx bytes {:02x} don't match ones received from rpc {:02x}", actual, from_rpc)] - TxBytesMismatch { from_rpc: BytesJson, actual: BytesJson }, + TxBytesMismatch { + from_rpc: BytesJson, + actual: BytesJson, + }, /// Provided transaction doesn't have output with specific index TxLacksOfOutputs, - /// Input payment timelock overflows the type used by specific coin. - LocktimeOverflow(String), + /// Indicates that overflow occurred, either while calculating a total payment or converting the timelock. + Overflow(String), /// Internal error + #[from_stringify("ethabi::Error")] Internal(String), + /// Payment transaction is in unexpected state. E.g., `Uninitialized` instead of `PaymentSent` for ETH payment. + UnexpectedPaymentState(String), + /// Payment transaction doesn't exist on-chain. + TxDoesNotExist(String), + /// Transaction has wrong properties, for example, it has been sent to a wrong address. + WrongPaymentTx(String), + ProtocolNotSupported(String), + InvalidData(String), } impl From for ValidateSwapV2TxError { @@ -1456,6 +1504,33 @@ impl From for ValidateSwapV2TxError { fn from(err: UtxoRpcError) -> Self { ValidateSwapV2TxError::Rpc(err.to_string()) } } +impl From for ValidateSwapV2TxError { + fn from(err: PaymentStatusErr) -> Self { + match err { + PaymentStatusErr::Internal(e) => ValidateSwapV2TxError::Internal(e), + PaymentStatusErr::Transport(e) => ValidateSwapV2TxError::Rpc(e), + PaymentStatusErr::ABIError(e) | PaymentStatusErr::InvalidData(e) => ValidateSwapV2TxError::InvalidData(e), + } + } +} + +impl From for ValidateSwapV2TxError { + fn from(err: ValidatePaymentV2Err) -> Self { + match err { + ValidatePaymentV2Err::UnexpectedPaymentState(e) => ValidateSwapV2TxError::UnexpectedPaymentState(e), + ValidatePaymentV2Err::WrongPaymentTx(e) => ValidateSwapV2TxError::WrongPaymentTx(e), + } + } +} + +impl From for ValidateSwapV2TxError { + fn from(err: PrepareTxDataError) -> Self { + match err { + PrepareTxDataError::ABIError(e) | PrepareTxDataError::Internal(e) => ValidateSwapV2TxError::Internal(e), + } + } +} + /// Enum covering error cases that can happen during taker funding spend preimage validation. #[derive(Debug, Display, EnumFromStringify)] pub enum ValidateTakerFundingSpendPreimageError { @@ -1634,7 +1709,7 @@ pub struct ValidateNftMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ParseNftA pub nft_swap_info: &'a NftSwapInfo<'a, Coin>, } -pub struct RefundMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { +pub struct RefundMakerPaymentSecretArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, /// Maker will be able to refund the payment after this timestamp @@ -1716,12 +1791,15 @@ pub trait MakerCoinSwapOpsV2: ParseCoinAssocTypes + CommonSwapOpsV2 + Send + Syn async fn validate_maker_payment_v2(&self, args: ValidateMakerPaymentArgs<'_, Self>) -> ValidatePaymentResult<()>; /// Refund maker payment transaction using timelock path - async fn refund_maker_payment_v2_timelock(&self, args: RefundPaymentArgs<'_>) -> Result; + async fn refund_maker_payment_v2_timelock( + &self, + args: RefundMakerPaymentTimelockArgs<'_>, + ) -> Result; /// Refund maker payment transaction using immediate refund path async fn refund_maker_payment_v2_secret( &self, - args: RefundMakerPaymentArgs<'_, Self>, + args: RefundMakerPaymentSecretArgs<'_, Self>, ) -> Result; /// Spend maker payment transaction @@ -1761,7 +1839,7 @@ pub trait MakerNftSwapOpsV2: ParseCoinAssocTypes + ParseNftAssocTypes + Send + S } /// Enum representing errors that can occur while waiting for taker payment spend. -#[derive(Display)] +#[derive(Display, Debug, EnumFromStringify)] pub enum WaitForTakerPaymentSpendError { /// Timeout error variant, indicating that the wait for taker payment spend has timed out. #[display( @@ -1775,9 +1853,14 @@ pub enum WaitForTakerPaymentSpendError { /// The current timestamp when the timeout occurred. now: u64, }, - /// Invalid input transaction error variant, containing additional information about the error. InvalidInputTx(String), + Internal(String), + #[from_stringify("ethabi::Error")] + #[display(fmt = "ABI error: {}", _0)] + ABIError(String), + InvalidData(String), + Transport(String), } impl From for WaitForTakerPaymentSpendError { @@ -1793,6 +1876,26 @@ impl From for WaitForTakerPaymentSpendError { } } +impl From for WaitForTakerPaymentSpendError { + fn from(e: PaymentStatusErr) -> Self { + match e { + PaymentStatusErr::ABIError(e) => Self::ABIError(e), + PaymentStatusErr::Transport(e) => Self::Transport(e), + PaymentStatusErr::Internal(e) => Self::Internal(e), + PaymentStatusErr::InvalidData(e) => Self::InvalidData(e), + } + } +} + +impl From for WaitForTakerPaymentSpendError { + fn from(e: PrepareTxDataError) -> Self { + match e { + PrepareTxDataError::ABIError(e) => Self::ABIError(e), + PrepareTxDataError::Internal(e) => Self::Internal(e), + } + } +} + /// Enum representing different ways a funding transaction can be spent. /// /// This enum is generic over types that implement the `ParseCoinAssocTypes` trait. @@ -1838,6 +1941,7 @@ pub enum SearchForFundingSpendErr { Rpc(String), /// Variant indicating an error during conversion of the `from_block` argument with associated `TryFromIntError`. FromBlockConversionErr(TryFromIntError), + Internal(String), } /// Operations specific to taker coin in [Trading Protocol Upgrade implementation](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1895) @@ -1851,7 +1955,8 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + CommonSwapOpsV2 + Send + Syn async fn validate_taker_funding(&self, args: ValidateTakerFundingArgs<'_, Self>) -> ValidateSwapV2TxResult; /// Refunds taker funding transaction using time-locked path without secret reveal. - async fn refund_taker_funding_timelock(&self, args: RefundPaymentArgs<'_>) -> Result; + async fn refund_taker_funding_timelock(&self, args: RefundTakerPaymentArgs<'_>) + -> Result; /// Reclaims taker funding transaction using immediate refund path with secret reveal. async fn refund_taker_funding_secret( @@ -1890,7 +1995,8 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + CommonSwapOpsV2 + Send + Syn ) -> Result; /// Refunds taker payment transaction. - async fn refund_combined_taker_payment(&self, args: RefundPaymentArgs<'_>) -> Result; + async fn refund_combined_taker_payment(&self, args: RefundTakerPaymentArgs<'_>) + -> Result; /// Generates and signs taker payment spend preimage. The preimage and signature should be /// shared with maker to proceed with protocol execution. diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 3ee9e7761b..b1d250c755 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -452,11 +452,11 @@ pub enum Qrc20AbiError { #[display(fmt = "Invalid QRC20 ABI params: {}", _0)] InvalidParams(String), #[display(fmt = "QRC20 ABI error: {}", _0)] - AbiError(String), + ABIError(String), } impl From for Qrc20AbiError { - fn from(e: ethabi::Error) -> Qrc20AbiError { Qrc20AbiError::AbiError(e.to_string()) } + fn from(e: ethabi::Error) -> Qrc20AbiError { Qrc20AbiError::ABIError(e.to_string()) } } impl From for ValidatePaymentError { diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index a5eaff2220..10b057ee77 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -1,8 +1,8 @@ #![allow(clippy::all)] use super::{CoinBalance, CommonSwapOpsV2, FundingTxSpend, HistorySyncState, MarketCoinOps, MmCoin, RawTransactionFut, - RawTransactionRequest, SearchForFundingSpendErr, SwapOps, TradeFee, TransactionEnum, TransactionFut, - WaitForTakerPaymentSpendError}; + RawTransactionRequest, RefundTakerPaymentArgs, SearchForFundingSpendErr, SwapOps, TradeFee, + TransactionEnum, TransactionFut, WaitForTakerPaymentSpendError}; use crate::coin_errors::ValidatePaymentResult; use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinFutSpawner, ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, GenPreimageResult, GenTakerFundingSpendArgs, @@ -472,7 +472,10 @@ impl TakerCoinSwapOpsV2 for TestCoin { unimplemented!() } - async fn refund_taker_funding_timelock(&self, args: RefundPaymentArgs<'_>) -> Result { + async fn refund_taker_funding_timelock( + &self, + args: RefundTakerPaymentArgs<'_>, + ) -> Result { todo!() } @@ -517,7 +520,10 @@ impl TakerCoinSwapOpsV2 for TestCoin { todo!() } - async fn refund_combined_taker_payment(&self, args: RefundPaymentArgs<'_>) -> Result { + async fn refund_combined_taker_payment( + &self, + args: RefundTakerPaymentArgs<'_>, + ) -> Result { unimplemented!() } diff --git a/mm2src/coins/utxo/qtum_delegation.rs b/mm2src/coins/utxo/qtum_delegation.rs index ad9aec86e1..f7573fafbf 100644 --- a/mm2src/coins/utxo/qtum_delegation.rs +++ b/mm2src/coins/utxo/qtum_delegation.rs @@ -45,7 +45,7 @@ pub enum QtumStakingAbiError { #[display(fmt = "Invalid QRC20 ABI params: {}", _0)] InvalidParams(String), #[display(fmt = "QRC20 ABI error: {}", _0)] - AbiError(String), + ABIError(String), #[display(fmt = "Qtum POD error: {}", _0)] PodSigningError(String), #[display(fmt = "Internal error: {}", _0)] @@ -56,7 +56,7 @@ impl From for QtumStakingAbiError { fn from(e: Qrc20AbiError) -> Self { match e { Qrc20AbiError::InvalidParams(e) => QtumStakingAbiError::InvalidParams(e), - Qrc20AbiError::AbiError(e) => QtumStakingAbiError::AbiError(e), + Qrc20AbiError::ABIError(e) => QtumStakingAbiError::ABIError(e), } } } @@ -66,7 +66,7 @@ impl From for DelegationError { } impl From for QtumStakingAbiError { - fn from(e: ethabi::Error) -> QtumStakingAbiError { QtumStakingAbiError::AbiError(e.to_string()) } + fn from(e: ethabi::Error) -> QtumStakingAbiError { QtumStakingAbiError::ABIError(e.to_string()) } } impl From for DelegationError { diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 12c18f602c..175454e1da 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -15,7 +15,7 @@ use crate::watcher_common::validate_watcher_reward; use crate::{scan_for_new_addresses_impl, CanRefundHtlc, CoinBalance, CoinWithDerivationMethod, ConfirmPaymentInput, DexFee, GenPreimageResult, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, GetWithdrawSenderAddress, RawTransactionError, RawTransactionRequest, RawTransactionRes, RawTransactionResult, - RefundFundingSecretArgs, RefundMakerPaymentArgs, RefundPaymentArgs, RewardTarget, + RefundFundingSecretArgs, RefundMakerPaymentSecretArgs, RefundPaymentArgs, RewardTarget, SearchForSwapTxSpendInput, SendMakerPaymentArgs, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SendTakerFundingArgs, SignRawTransactionEnum, SignRawTransactionRequest, SignUtxoTransactionParams, SignatureError, SignatureResult, SpendMakerPaymentArgs, SpendPaymentArgs, SwapOps, @@ -2871,13 +2871,12 @@ pub async fn wait_for_output_spend_impl( wait_until: u64, check_every: f64, ) -> MmResult { + let script_pubkey = &tx + .outputs + .get(output_index) + .or_mm_err(|| WaitForOutputSpendErr::NoOutputWithIndex(output_index))? + .script_pubkey; loop { - let script_pubkey = &tx - .outputs - .get(output_index) - .or_mm_err(|| WaitForOutputSpendErr::NoOutputWithIndex(output_index))? - .script_pubkey; - match coin .rpc_client .find_output_spend( @@ -4886,14 +4885,14 @@ where let expected_amount_sat = sat_from_big_decimal(&total_expected_amount, coin.as_ref().decimals)?; let time_lock = args - .time_lock + .funding_time_lock .try_into() - .map_to_mm(|e: TryFromIntError| ValidateSwapV2TxError::LocktimeOverflow(e.to_string()))?; + .map_to_mm(|e: TryFromIntError| ValidateSwapV2TxError::Overflow(e.to_string()))?; let redeem_script = swap_proto_v2_scripts::taker_funding_script( time_lock, args.taker_secret_hash, - args.other_pub, + args.taker_pub, maker_htlc_key_pair.public(), ); let expected_output = TransactionOutput { @@ -5069,7 +5068,7 @@ pub async fn spend_maker_payment_v2( /// Common implementation of maker payment v2 reclaim for UTXO coins using immediate refund path with secret reveal. pub async fn refund_maker_payment_v2_secret( coin: T, - args: RefundMakerPaymentArgs<'_, T>, + args: RefundMakerPaymentSecretArgs<'_, T>, ) -> Result where T: UtxoCommonOps + SwapOps, diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 6baaf9d180..d55ce40420 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -27,18 +27,18 @@ use crate::{CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinBalance, CoinWithDeriva GenTakerPaymentSpendArgs, GetWithdrawSenderAddress, IguanaBalanceOps, IguanaPrivKey, MakerCoinSwapOpsV2, MakerSwapTakerCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, PrivKeyBuildPolicy, RawTransactionRequest, RawTransactionResult, RefundError, - RefundFundingSecretArgs, RefundMakerPaymentArgs, RefundPaymentArgs, RefundResult, - SearchForFundingSpendErr, SearchForSwapTxSpendInput, SendMakerPaymentArgs, - SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SendTakerFundingArgs, SignRawTransactionRequest, - SignatureResult, SpendMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, - TakerCoinSwapOpsV2, TakerSwapMakerCoin, ToBytes, TradePreimageValue, TransactionFut, TransactionResult, - TxMarshalingErr, TxPreimageWithSig, ValidateAddressResult, ValidateFeeArgs, ValidateInstructionsErr, - ValidateMakerPaymentArgs, ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentFut, - ValidatePaymentInput, ValidateSwapV2TxResult, ValidateTakerFundingArgs, - ValidateTakerFundingSpendPreimageResult, ValidateTakerPaymentSpendPreimageResult, - ValidateWatcherSpendInput, VerificationResult, WaitForHTLCTxSpendArgs, WaitForTakerPaymentSpendError, - WatcherOps, WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, - WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, WithdrawFut}; + RefundFundingSecretArgs, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, RefundPaymentArgs, + RefundResult, RefundTakerPaymentArgs, SearchForFundingSpendErr, SearchForSwapTxSpendInput, + SendMakerPaymentArgs, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SendTakerFundingArgs, + SignRawTransactionRequest, SignatureResult, SpendMakerPaymentArgs, SpendPaymentArgs, SwapOps, + SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, TakerSwapMakerCoin, ToBytes, TradePreimageValue, + TransactionFut, TransactionResult, TxMarshalingErr, TxPreimageWithSig, ValidateAddressResult, + ValidateFeeArgs, ValidateInstructionsErr, ValidateMakerPaymentArgs, ValidateOtherPubKeyErr, + ValidatePaymentError, ValidatePaymentFut, ValidatePaymentInput, ValidateSwapV2TxResult, + ValidateTakerFundingArgs, ValidateTakerFundingSpendPreimageResult, + ValidateTakerPaymentSpendPreimageResult, ValidateWatcherSpendInput, VerificationResult, + WaitForHTLCTxSpendArgs, WaitForTakerPaymentSpendError, WatcherOps, WatcherReward, WatcherRewardError, + WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, WithdrawFut}; use common::executor::{AbortableSystem, AbortedError}; use futures::{FutureExt, TryFutureExt}; use mm2_metrics::MetricsArc; @@ -637,13 +637,25 @@ impl MakerCoinSwapOpsV2 for UtxoStandardCoin { .await } - async fn refund_maker_payment_v2_timelock(&self, args: RefundPaymentArgs<'_>) -> Result { + async fn refund_maker_payment_v2_timelock( + &self, + args: RefundMakerPaymentTimelockArgs<'_>, + ) -> Result { + let args = RefundPaymentArgs { + payment_tx: args.payment_tx, + time_lock: args.time_lock, + other_pubkey: args.taker_pub, + tx_type_with_secret_hash: args.tx_type_with_secret_hash, + swap_contract_address: &None, + swap_unique_data: args.swap_unique_data, + watcher_reward: args.watcher_reward, + }; utxo_common::refund_htlc_payment(self.clone(), args).await } async fn refund_maker_payment_v2_secret( &self, - args: RefundMakerPaymentArgs<'_, Self>, + args: RefundMakerPaymentSecretArgs<'_, Self>, ) -> Result { utxo_common::refund_maker_payment_v2_secret(self.clone(), args).await } @@ -663,7 +675,19 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { utxo_common::validate_taker_funding(self, args).await } - async fn refund_taker_funding_timelock(&self, args: RefundPaymentArgs<'_>) -> Result { + async fn refund_taker_funding_timelock( + &self, + args: RefundTakerPaymentArgs<'_>, + ) -> Result { + let args = RefundPaymentArgs { + payment_tx: args.payment_tx, + time_lock: args.time_lock, + other_pubkey: args.maker_pub, + tx_type_with_secret_hash: args.tx_type_with_secret_hash, + swap_contract_address: &None, + swap_unique_data: args.swap_unique_data, + watcher_reward: args.watcher_reward, + }; utxo_common::refund_htlc_payment(self.clone(), args).await } @@ -775,7 +799,19 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { utxo_common::sign_and_send_taker_funding_spend(self, preimage, args, &htlc_keypair).await } - async fn refund_combined_taker_payment(&self, args: RefundPaymentArgs<'_>) -> Result { + async fn refund_combined_taker_payment( + &self, + args: RefundTakerPaymentArgs<'_>, + ) -> Result { + let args = RefundPaymentArgs { + payment_tx: args.payment_tx, + time_lock: args.time_lock, + other_pubkey: args.maker_pub, + tx_type_with_secret_hash: args.tx_type_with_secret_hash, + swap_contract_address: &None, + swap_unique_data: args.swap_unique_data, + watcher_reward: args.watcher_reward, + }; utxo_common::refund_htlc_payment(self.clone(), args).await } diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 6ec1dcf360..6029bd61b2 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -9,8 +9,8 @@ use crate::lp_swap::{swap_v2_pb::*, NO_REFUND_FEE}; use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; use coins::{CanRefundHtlc, ConfirmPaymentInput, DexFee, FeeApproxStage, FundingTxSpend, GenTakerFundingSpendArgs, - GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, ParseCoinAssocTypes, RefundMakerPaymentArgs, - RefundPaymentArgs, SearchForFundingSpendErr, SendMakerPaymentArgs, SwapTxTypeWithSecretHash, + GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, + RefundMakerPaymentTimelockArgs, SearchForFundingSpendErr, SendMakerPaymentArgs, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, TradePreimageValue, Transaction, TxPreimageWithSig, ValidateTakerFundingArgs}; use common::executor::abortable_queue::AbortableQueue; use common::executor::{AbortableSystem, Timer}; @@ -353,7 +353,8 @@ pub struct MakerSwapStateMachine { + | e @ SearchForFundingSpendErr::FromBlockConversionErr(_) + | e @ SearchForFundingSpendErr::Internal(_) => { let next_state = MakerPaymentRefundRequired { maker_coin_start_block: self.maker_coin_start_block, taker_coin_start_block: self.taker_coin_start_block, @@ -1446,7 +1451,7 @@ impl> = Mutex::new(Vec::with_capacity(18)); - pub static ref MM_CTX: MmArc = MmCtxBuilder::new().into_mm_arc(); + pub static ref MM_CTX: MmArc = MmCtxBuilder::new().with_conf(json!({"use_trading_proto_v2": true})).into_mm_arc(); /// We need a second `MmCtx` instance when we use the same private keys for Maker and Taker across various tests. /// When enabling coins for both Maker and Taker, two distinct coin instances are created. /// This means that different instances of the same coin should have separate global nonce locks. /// Utilizing different `MmCtx` instances allows us to assign Maker and Taker coins to separate `CoinsCtx`. /// This approach addresses the `replacement transaction` issue, which occurs when different transactions share the same nonce. - pub static ref MM_CTX1: MmArc = MmCtxBuilder::new().into_mm_arc(); + pub static ref MM_CTX1: MmArc = MmCtxBuilder::new().with_conf(json!({"use_trading_proto_v2": true})).into_mm_arc(); pub static ref GETH_WEB3: Web3 = Web3::new(Http::new(GETH_RPC_URL).unwrap()); pub static ref SEPOLIA_WEB3: Web3 = Web3::new(Http::new(SEPOLIA_RPC_URL).unwrap()); // Mutex used to prevent nonce re-usage during funding addresses used in tests @@ -80,28 +79,25 @@ pub static mut QTUM_CONF_PATH: Option = None; pub static mut GETH_ACCOUNT: H160Eth = H160Eth::zero(); /// ERC20 token address on Geth dev node pub static mut GETH_ERC20_CONTRACT: H160Eth = H160Eth::zero(); +pub static mut SEPOLIA_ERC20_CONTRACT: H160Eth = H160Eth::zero(); /// Swap contract address on Geth dev node pub static mut GETH_SWAP_CONTRACT: H160Eth = H160Eth::zero(); /// Maker Swap V2 contract address on Geth dev node pub static mut GETH_MAKER_SWAP_V2: H160Eth = H160Eth::zero(); /// Taker Swap V2 contract address on Geth dev node pub static mut GETH_TAKER_SWAP_V2: H160Eth = H160Eth::zero(); +pub static mut SEPOLIA_TAKER_SWAP_V2: H160Eth = H160Eth::zero(); +pub static mut SEPOLIA_MAKER_SWAP_V2: H160Eth = H160Eth::zero(); /// Swap contract (with watchers support) address on Geth dev node pub static mut GETH_WATCHERS_SWAP_CONTRACT: H160Eth = H160Eth::zero(); /// ERC721 token address on Geth dev node pub static mut GETH_ERC721_CONTRACT: H160Eth = H160Eth::zero(); /// ERC1155 token address on Geth dev node pub static mut GETH_ERC1155_CONTRACT: H160Eth = H160Eth::zero(); -/// Nft Swap contract address on Geth dev node -pub static mut GETH_NFT_SWAP_CONTRACT: H160Eth = H160Eth::zero(); /// NFT Maker Swap V2 contract address on Geth dev node pub static mut GETH_NFT_MAKER_SWAP_V2: H160Eth = H160Eth::zero(); /// NFT Maker Swap V2 contract address on Sepolia testnet pub static mut SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2: H160Eth = H160Eth::zero(); -/// ERC721 token address on Sepolia testnet -pub static mut SEPOLIA_ERC721_CONTRACT: H160Eth = H160Eth::zero(); -/// ERC1155 token address on Sepolia testnet -pub static mut SEPOLIA_ERC1155_CONTRACT: H160Eth = H160Eth::zero(); pub static GETH_RPC_URL: &str = "http://127.0.0.1:8545"; pub static SEPOLIA_RPC_URL: &str = "https://ethereum-sepolia-rpc.publicnode.com"; @@ -134,9 +130,7 @@ pub const ERC721_TEST_TOKEN_BYTES: &str = include_str!("../../../mm2_test_helpers/contract_bytes/erc721_test_token_bytes"); pub const ERC1155_TEST_TOKEN_BYTES: &str = include_str!("../../../mm2_test_helpers/contract_bytes/erc1155_test_token_bytes"); -pub const NFT_SWAP_CONTRACT_BYTES: &str = - include_str!("../../../mm2_test_helpers/contract_bytes/nft_swap_contract_bytes"); -/// https://github.com/KomodoPlatform/etomic-swap/blob/006e6fd52334530f23624a2139d0eb5299c4cd10/contracts/EtomicSwapMakerNftV2Test.sol +/// https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerNftV2.sol pub const NFT_MAKER_SWAP_V2_BYTES: &str = include_str!("../../../mm2_test_helpers/contract_bytes/nft_maker_swap_v2_bytes"); /// https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerNftV2.sol @@ -1444,50 +1438,6 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } - let dex_fee_address = Token::Address(geth_account()); - let params = ethabi::encode(&[dex_fee_address]); - let nft_swap_data = format!("{}{}", NFT_SWAP_CONTRACT_BYTES, hex::encode(params)); - - let tx_request_deploy_nft_swap_contract = TransactionRequest { - from: GETH_ACCOUNT, - to: None, - gas: None, - gas_price: None, - value: None, - data: Some(hex::decode(nft_swap_data).unwrap().into()), - nonce: None, - condition: None, - transaction_type: None, - access_list: None, - max_fee_per_gas: None, - max_priority_fee_per_gas: None, - }; - let deploy_nft_swap_tx_hash = - block_on(GETH_WEB3.eth().send_transaction(tx_request_deploy_nft_swap_contract)).unwrap(); - log!("Sent deploy nft swap contract transaction {:?}", deploy_swap_tx_hash); - - loop { - let deploy_nft_swap_tx_receipt = - match block_on(GETH_WEB3.eth().transaction_receipt(deploy_nft_swap_tx_hash)) { - Ok(receipt) => receipt, - Err(_) => { - thread::sleep(Duration::from_millis(100)); - continue; - }, - }; - - if let Some(receipt) = deploy_nft_swap_tx_receipt { - GETH_NFT_SWAP_CONTRACT = receipt.contract_address.unwrap(); - log!( - "GETH_NFT_SWAP_CONTRACT {:?}, receipt.status {:?}", - GETH_NFT_SWAP_CONTRACT, - receipt.status - ); - break; - } - thread::sleep(Duration::from_millis(100)); - } - let tx_request_deploy_nft_maker_swap_v2_contract = TransactionRequest { from: GETH_ACCOUNT, to: None, @@ -1535,50 +1485,6 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } - let dex_fee_address = Token::Address(geth_account()); - let params = ethabi::encode(&[dex_fee_address]); - let nft_swap_data = format!("{}{}", NFT_SWAP_CONTRACT_BYTES, hex::encode(params)); - - let tx_request_deploy_nft_swap_contract = TransactionRequest { - from: GETH_ACCOUNT, - to: None, - gas: None, - gas_price: None, - value: None, - data: Some(hex::decode(nft_swap_data).unwrap().into()), - nonce: None, - condition: None, - transaction_type: None, - access_list: None, - max_fee_per_gas: None, - max_priority_fee_per_gas: None, - }; - let deploy_nft_swap_tx_hash = - block_on(GETH_WEB3.eth().send_transaction(tx_request_deploy_nft_swap_contract)).unwrap(); - log!("Sent deploy nft swap contract transaction {:?}", deploy_swap_tx_hash); - - loop { - let deploy_nft_swap_tx_receipt = - match block_on(GETH_WEB3.eth().transaction_receipt(deploy_nft_swap_tx_hash)) { - Ok(receipt) => receipt, - Err(_) => { - thread::sleep(Duration::from_millis(100)); - continue; - }, - }; - - if let Some(receipt) = deploy_nft_swap_tx_receipt { - GETH_NFT_SWAP_CONTRACT = receipt.contract_address.unwrap(); - log!( - "GETH_NFT_SWAP_CONTRACT {:?}, receipt.status {:?}", - GETH_NFT_SWAP_CONTRACT, - receipt.status - ); - break; - } - thread::sleep(Duration::from_millis(100)); - } - let name = Token::String("MyNFT".into()); let symbol = Token::String("MNFT".into()); let params = ethabi::encode(&[name, symbol]); @@ -1658,8 +1564,10 @@ pub fn init_geth_node() { } SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 = EthAddress::from_str("0x9eb88cd58605d8fb9b14652d6152727f7e95fb4d").unwrap(); - SEPOLIA_ERC721_CONTRACT = EthAddress::from_str("0xbac1c9f2087f39caaa4e93412c6412809186870e").unwrap(); - SEPOLIA_ERC1155_CONTRACT = EthAddress::from_str("0xfb53b8764be6033d89ceacafa36631b09d60a1d2").unwrap(); + SEPOLIA_ERC20_CONTRACT = EthAddress::from_str("0xF7b5F8E8555EF7A743f24D3E974E23A3C6cB6638").unwrap(); + SEPOLIA_TAKER_SWAP_V2 = EthAddress::from_str("0x7Cc9F2c1c3B797D09B9d1CCd7FDcD2539a4b3874").unwrap(); + // TODO update this + SEPOLIA_MAKER_SWAP_V2 = EthAddress::from_str("0x7Cc9F2c1c3B797D09B9d1CCd7FDcD2539a4b3874").unwrap(); let alice_passphrase = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); let alice_keypair = key_pair_from_seed(&alice_passphrase).unwrap(); diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 7d56820de7..3a898b0f2f 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1,116 +1,92 @@ use super::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC721_TEST_ABI, GETH_ACCOUNT, GETH_ERC1155_CONTRACT, GETH_ERC20_CONTRACT, GETH_ERC721_CONTRACT, GETH_MAKER_SWAP_V2, - GETH_NFT_MAKER_SWAP_V2, GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, GETH_RPC_URL, - GETH_SWAP_CONTRACT, GETH_TAKER_SWAP_V2, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, - MM_CTX, SEPOLIA_ERC1155_CONTRACT, SEPOLIA_ERC721_CONTRACT, - SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2, SEPOLIA_NONCE_LOCK, SEPOLIA_RPC_URL, SEPOLIA_WEB3}; + GETH_NFT_MAKER_SWAP_V2, GETH_NONCE_LOCK, GETH_RPC_URL, GETH_SWAP_CONTRACT, + GETH_TAKER_SWAP_V2, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX, MM_CTX1, + SEPOLIA_ERC20_CONTRACT, SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2, SEPOLIA_MAKER_SWAP_V2, + SEPOLIA_NONCE_LOCK, SEPOLIA_RPC_URL, SEPOLIA_TAKER_SWAP_V2, SEPOLIA_WEB3}; use crate::common::Future01CompatExt; use bitcrypto::{dhash160, sha256}; use coins::eth::gas_limit::ETH_MAX_TRADE_GAS; -use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, SignedEthTx, ERC20_ABI}; +use coins::eth::v2_activation::{eth_coin_from_conf_and_request_v2, EthActivationV2Request, EthNode}; +use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, EthCoinType, + EthPrivKeyBuildPolicy, SignedEthTx, SwapV2Contracts, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; use coins::{lp_coinfind, CoinProtocol, CoinWithDerivationMethod, CoinsContext, CommonSwapOpsV2, ConfirmPaymentInput, - DerivationMethod, Eip1559Ops, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, MmCoinEnum, - MmCoinStruct, NftSwapInfo, ParseCoinAssocTypes, ParseNftAssocTypes, PrivKeyBuildPolicy, - RefundNftMakerPaymentArgs, RefundPaymentArgs, SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, - SendPaymentArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxFeePolicy, - SwapTxTypeWithSecretHash, ToBytes, Transaction, ValidateNftMakerPaymentArgs}; + DerivationMethod, DexFee, Eip1559Ops, FoundSwapTxSpend, FundingTxSpend, GenTakerFundingSpendArgs, + GenTakerPaymentSpendArgs, MakerNftSwapOpsV2, MarketCoinOps, MmCoinEnum, MmCoinStruct, NftSwapInfo, + ParseCoinAssocTypes, ParseNftAssocTypes, PrivKeyBuildPolicy, RefundFundingSecretArgs, + RefundNftMakerPaymentArgs, RefundPaymentArgs, RefundTakerPaymentArgs, SearchForSwapTxSpendInput, + SendNftMakerPaymentArgs, SendPaymentArgs, SendTakerFundingArgs, SpendNftMakerPaymentArgs, + SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, + Transaction, TxPreimageWithSig, ValidateNftMakerPaymentArgs, ValidateTakerFundingArgs}; use common::{block_on, now_sec}; use crypto::Secp256k1Secret; -use ethcore_transaction::Action; use ethereum_types::U256; use futures01::Future; use mm2_core::mm_ctx::MmArc; use mm2_number::{BigDecimal, BigUint}; -use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf, nft_sepolia_conf}; +use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, eth_sepolia_conf, nft_dev_conf, sepolia_erc20_dev_conf}; +use serde_json::Value as Json; +use std::str::FromStr; use std::thread; use std::time::Duration; use web3::contract::{Contract, Options}; use web3::ethabi::Token; use web3::types::{Address, BlockNumber, TransactionRequest, H256}; -#[allow(dead_code)] const SEPOLIA_MAKER_PRIV: &str = "6e2f3a6223b928a05a3a3622b0c3f3573d03663b704a61a6eb73326de0487928"; -#[allow(dead_code)] const SEPOLIA_TAKER_PRIV: &str = "e0be82dca60ff7e4c6d6db339ac9e1ae249af081dba2110bddd281e711608f16"; const NFT_ETH: &str = "NFT_ETH"; +const ETH: &str = "ETH"; +const ERC20: &str = "ERC20DEV"; /// # Safety /// /// GETH_ACCOUNT is set once during initialization before tests start pub fn geth_account() -> Address { unsafe { GETH_ACCOUNT } } - /// # Safety /// /// GETH_SWAP_CONTRACT is set once during initialization before tests start pub fn swap_contract() -> Address { unsafe { GETH_SWAP_CONTRACT } } - -#[allow(dead_code)] /// # Safety /// /// GETH_MAKER_SWAP_V2 is set once during initialization before tests start pub fn maker_swap_v2() -> Address { unsafe { GETH_MAKER_SWAP_V2 } } - -#[allow(dead_code)] /// # Safety /// /// GETH_TAKER_SWAP_V2 is set once during initialization before tests start pub fn taker_swap_v2() -> Address { unsafe { GETH_TAKER_SWAP_V2 } } - -#[allow(dead_code)] -/// # Safety -/// -/// GETH_NFT_SWAP_CONTRACT is set once during initialization before tests start -pub fn nft_swap_contract() -> Address { unsafe { GETH_NFT_SWAP_CONTRACT } } - +pub fn sepolia_taker_swap_v2() -> Address { unsafe { SEPOLIA_TAKER_SWAP_V2 } } +pub fn sepolia_maker_swap_v2() -> Address { unsafe { SEPOLIA_MAKER_SWAP_V2 } } /// # Safety /// /// GETH_NFT_MAKER_SWAP_V2 is set once during initialization before tests start pub fn geth_nft_maker_swap_v2() -> Address { unsafe { GETH_NFT_MAKER_SWAP_V2 } } - /// # Safety /// /// GETH_WATCHERS_SWAP_CONTRACT is set once during initialization before tests start pub fn watchers_swap_contract() -> Address { unsafe { GETH_WATCHERS_SWAP_CONTRACT } } - /// # Safety /// /// GETH_ERC20_CONTRACT is set once during initialization before tests start pub fn erc20_contract() -> Address { unsafe { GETH_ERC20_CONTRACT } } - +pub fn sepolia_erc20_contract() -> Address { unsafe { SEPOLIA_ERC20_CONTRACT } } /// Return ERC20 dev token contract address in checksum format pub fn erc20_contract_checksum() -> String { checksum_address(&format!("{:02x}", erc20_contract())) } - -#[allow(dead_code)] +pub fn sepolia_erc20_contract_checksum() -> String { checksum_address(&format!("{:02x}", sepolia_erc20_contract())) } /// # Safety /// /// GETH_ERC721_CONTRACT is set once during initialization before tests start pub fn geth_erc721_contract() -> Address { unsafe { GETH_ERC721_CONTRACT } } - -#[allow(dead_code)] /// # Safety /// /// GETH_ERC1155_CONTRACT is set once during initialization before tests start pub fn geth_erc1155_contract() -> Address { unsafe { GETH_ERC1155_CONTRACT } } - -#[allow(dead_code)] /// # Safety /// /// SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 address is set once during initialization before tests start pub fn sepolia_etomic_maker_nft() -> Address { unsafe { SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 } } -#[allow(dead_code)] -/// # Safety -/// -/// SEPOLIA_ERC721_CONTRACT address is set once during initialization before tests start -pub fn sepolia_erc721() -> Address { unsafe { SEPOLIA_ERC721_CONTRACT } } - -#[allow(dead_code)] -/// # Safety -/// -/// SEPOLIA_ERC1155_CONTRACT address is set once during initialization before tests start -pub fn sepolia_erc1155() -> Address { unsafe { SEPOLIA_ERC1155_CONTRACT } } - fn wait_for_confirmation(tx_hash: H256) { thread::sleep(Duration::from_millis(2000)); loop { @@ -233,7 +209,7 @@ fn mint_erc1155(to_addr: Address, token_id: U256, amount: U256) { } fn geth_erc1155_balance(wallet_addr: Address, token_id: U256) -> U256 { - let _guard = SEPOLIA_NONCE_LOCK.lock().unwrap(); + let _guard = GETH_NONCE_LOCK.lock().unwrap(); let erc1155_contract = Contract::from_json(GETH_WEB3.eth(), geth_erc1155_contract(), ERC1155_TEST_ABI.as_bytes()).unwrap(); block_on(erc1155_contract.query( @@ -360,29 +336,47 @@ pub enum TestNftType { /// Generates a global NFT coin instance with a random private key and an initial 100 ETH balance. /// Optionally mints a specified NFT (either ERC721 or ERC1155) to the global NFT address, /// with details recorded in the `nfts_infos` field based on the provided `nft_type`. -#[allow(dead_code)] -pub fn global_nft_with_random_privkey(swap_contract_address: Address, nft_type: Option) -> EthCoin { - let nft_conf = nft_dev_conf(); - let req = json!({ - "method": "enable", - "coin": "NFT_ETH", - "urls": [GETH_RPC_URL], - "swap_contract_address": swap_contract_address, - }); - - let global_nft = block_on(eth_coin_from_conf_and_request( - &MM_CTX, - "NFT_ETH", - &nft_conf, - &req, - CoinProtocol::NFT { - platform: "ETH".to_string(), - }, - PrivKeyBuildPolicy::IguanaPrivKey(random_secp256k1_secret()), +fn global_nft_with_random_privkey( + swap_v2_contracts: SwapV2Contracts, + swap_contract_address: Address, + fallback_swap_contract_address: Address, + nft_type: Option, + nft_ticker: String, + platform_ticker: String, +) -> EthCoin { + let build_policy = EthPrivKeyBuildPolicy::IguanaPrivKey(random_secp256k1_secret()); + let node = EthNode { + url: GETH_RPC_URL.to_string(), + komodo_proxy: false, + }; + let platform_request = EthActivationV2Request { + nodes: vec![node], + rpc_mode: Default::default(), + swap_contract_address, + swap_v2_contracts: Some(swap_v2_contracts), + fallback_swap_contract: Some(fallback_swap_contract_address), + contract_supports_watchers: false, + mm2: None, + required_confirmations: None, + priv_key_policy: Default::default(), + enable_params: Default::default(), + path_to_address: Default::default(), + gap_limit: None, + }; + let coin = block_on(eth_coin_from_conf_and_request_v2( + &MM_CTX1, + nft_ticker.as_str(), + &nft_dev_conf(), + platform_request, + build_policy, )) .unwrap(); - let my_address = block_on(global_nft.my_addr()); + let coin_type = EthCoinType::Nft { + platform: platform_ticker, + }; + let global_nft = block_on(coin.set_coin_type(coin_type)); + let my_address = block_on(coin.my_addr()); fill_eth(my_address, U256::from(10).pow(U256::from(20))); if let Some(nft_type) = nft_type { @@ -402,114 +396,77 @@ pub fn global_nft_with_random_privkey(swap_contract_address: Address, nft_type: }, } } - global_nft } -#[allow(dead_code)] -/// Can be used to generate global NFT from Sepolia Maker/Taker priv keys. -fn global_nft_from_privkey( - ctx: &MmArc, - swap_contract_address: Address, - secret: &'static str, - nft_type: Option, -) -> EthCoin { - let nft_conf = nft_sepolia_conf(); - let req = json!({ - "method": "enable", - "coin": "NFT_ETH", - "urls": [SEPOLIA_RPC_URL], - "swap_contract_address": swap_contract_address, - }); +/// Can be used to generate coin from Sepolia Maker/Taker priv keys. +fn sepolia_coin_from_privkey(ctx: &MmArc, secret: &'static str, ticker: &str, conf: &Json, erc20: bool) -> EthCoin { + let swap_addr = SwapAddresses { + swap_v2_contracts: SwapV2Contracts { + maker_swap_v2_contract: sepolia_maker_swap_v2(), + taker_swap_v2_contract: sepolia_taker_swap_v2(), + nft_maker_swap_v2_contract: sepolia_etomic_maker_nft(), + }, + swap_contract_address: sepolia_taker_swap_v2(), + fallback_swap_contract_address: sepolia_taker_swap_v2(), + }; let priv_key = Secp256k1Secret::from(secret); - let global_nft = block_on(eth_coin_from_conf_and_request( + let build_policy = EthPrivKeyBuildPolicy::IguanaPrivKey(priv_key); + + let node = EthNode { + url: SEPOLIA_RPC_URL.to_string(), + komodo_proxy: false, + }; + let platform_request = EthActivationV2Request { + nodes: vec![node], + rpc_mode: Default::default(), + swap_contract_address: swap_addr.swap_contract_address, + swap_v2_contracts: Some(swap_addr.swap_v2_contracts), + fallback_swap_contract: Some(swap_addr.fallback_swap_contract_address), + contract_supports_watchers: false, + mm2: None, + required_confirmations: None, + priv_key_policy: Default::default(), + enable_params: Default::default(), + path_to_address: Default::default(), + gap_limit: None, + }; + let coin = block_on(eth_coin_from_conf_and_request_v2( ctx, - NFT_ETH, - &nft_conf, - &req, - CoinProtocol::NFT { - platform: "ETH".to_string(), - }, - PrivKeyBuildPolicy::IguanaPrivKey(priv_key), + ticker, + conf, + platform_request, + build_policy, )) .unwrap(); + let coin = if erc20 { + let coin_type = EthCoinType::Erc20 { + platform: ETH.to_string(), + token_addr: sepolia_erc20_contract(), + }; + block_on(coin.set_coin_type(coin_type)) + } else { + coin + }; let coins_ctx = CoinsContext::from_ctx(ctx).unwrap(); let mut coins = block_on(coins_ctx.lock_coins()); coins.insert( - global_nft.ticker().into(), - MmCoinStruct::new(MmCoinEnum::EthCoin(global_nft.clone())), + coin.ticker().into(), + MmCoinStruct::new(MmCoinEnum::EthCoin(coin.clone())), ); - - if let Some(nft_type) = nft_type { - match nft_type { - TestNftType::Erc1155 { token_id, amount } => { - block_on(fill_erc1155_info(&global_nft, sepolia_erc1155(), token_id, amount)); - }, - TestNftType::Erc721 { token_id } => { - block_on(fill_erc721_info(&global_nft, sepolia_erc721(), token_id)); - }, - } - } - - global_nft + coin } -#[allow(dead_code)] -fn send_safe_transfer_from( - global_nft: &EthCoin, - token_address: Address, - from_address: Address, - to_address: Address, - nft_type: TestNftType, -) -> web3::Result { - let _guard = SEPOLIA_NONCE_LOCK.lock().unwrap(); - - let contract = match nft_type { - TestNftType::Erc1155 { .. } => { - Contract::from_json(SEPOLIA_WEB3.eth(), token_address, ERC1155_TEST_ABI.as_bytes()).unwrap() - }, - TestNftType::Erc721 { .. } => { - Contract::from_json(SEPOLIA_WEB3.eth(), token_address, ERC721_TEST_ABI.as_bytes()).unwrap() +fn get_or_create_sepolia_coin(ctx: &MmArc, priv_key: &'static str, ticker: &str, conf: &Json, erc20: bool) -> EthCoin { + match block_on(lp_coinfind(ctx, ticker)).unwrap() { + None => sepolia_coin_from_privkey(ctx, priv_key, ticker, conf, erc20), + Some(mm_coin) => match mm_coin { + MmCoinEnum::EthCoin(coin) => coin, + _ => panic!("Unexpected coin type found. Expected MmCoinEnum::EthCoin"), }, - }; - let tokens = match nft_type { - TestNftType::Erc1155 { token_id, amount } => vec![ - Token::Address(from_address), - Token::Address(to_address), - Token::Uint(U256::from(token_id)), - Token::Uint(U256::from(amount)), - Token::Bytes(vec![]), - ], - TestNftType::Erc721 { token_id } => vec![ - Token::Address(from_address), - Token::Address(to_address), - Token::Uint(U256::from(token_id)), - ], - }; - - let data = contract - .abi() - .function("safeTransferFrom") - .unwrap() - .encode_input(&tokens) - .unwrap(); - - let result = block_on( - global_nft - .sign_and_send_transaction( - 0.into(), - Action::Call(token_address), - data, - U256::from(ETH_MAX_TRADE_GAS), - ) - .compat(), - ) - .unwrap(); - - log!("Transaction sent: {:?}", result); - Ok(result) + } } /// Fills the private key's public address with ETH and ERC20 tokens @@ -902,7 +859,6 @@ fn send_and_spend_erc20_maker_payment_priority_fee() { send_and_spend_erc20_maker_payment_impl(SwapTxFeePolicy::Medium); } -#[allow(dead_code)] /// Wait for all pending transactions for the given address to be confirmed fn wait_pending_transactions(wallet_address: Address) { let _guard = SEPOLIA_NONCE_LOCK.lock().unwrap(); @@ -913,7 +869,10 @@ fn wait_pending_transactions(wallet_address: Address) { let pending_nonce = block_on(web3.eth().transaction_count(wallet_address, Some(BlockNumber::Pending))).unwrap(); if latest_nonce == pending_nonce { - log!("All pending transactions have been confirmed."); + log!( + "All pending transactions have been confirmed. Latest nonce: {}", + latest_nonce + ); break; } else { log!( @@ -926,29 +885,18 @@ fn wait_pending_transactions(wallet_address: Address) { } } -#[allow(dead_code)] -fn get_or_create_nft(ctx: &MmArc, priv_key: &'static str, nft_type: Option) -> EthCoin { - match block_on(lp_coinfind(ctx, NFT_ETH)).unwrap() { - None => global_nft_from_privkey(ctx, sepolia_etomic_maker_nft(), priv_key, nft_type), - Some(mm_coin) => match mm_coin { - MmCoinEnum::EthCoin(nft) => nft, - _ => panic!("Unexpected coin type found. Expected MmCoinEnum::EthCoin"), - }, - } -} - #[test] fn send_and_spend_erc721_maker_payment() { - thread::sleep(Duration::from_secs(11)); let token_id = 1u32; let time_lock = now_sec() + 1000; + let activation = NftActivationV2Args::init(); let setup = setup_test( token_id, None, ContractType::Erc721, - geth_nft_maker_swap_v2(), geth_erc721_contract(), time_lock, + activation, ); let maker_payment = send_nft_maker_payment(&setup, 1.into()); @@ -974,17 +922,17 @@ fn send_and_spend_erc721_maker_payment() { #[test] fn send_and_spend_erc1155_maker_payment() { - thread::sleep(Duration::from_secs(3)); let token_id = 1u32; let amount = 3u32; let time_lock = now_sec() + 1000; + let activation = NftActivationV2Args::init(); let setup = setup_test( token_id, Some(amount), ContractType::Erc1155, - geth_nft_maker_swap_v2(), geth_erc1155_contract(), time_lock, + activation, ); let maker_address = block_on(setup.maker_global_nft.my_addr()); @@ -1049,16 +997,16 @@ fn test_nonce_lock() { #[test] fn send_and_refund_erc721_maker_payment_timelock() { - thread::sleep(Duration::from_secs(39)); let token_id = 2u32; let time_lock_to_refund = now_sec() - 1000; + let activation = NftActivationV2Args::init(); let setup = setup_test( token_id, None, ContractType::Erc721, - geth_nft_maker_swap_v2(), geth_erc721_contract(), time_lock_to_refund, + activation, ); let maker_payment_to_refund = send_nft_maker_payment(&setup, 1.into()); @@ -1090,17 +1038,17 @@ fn send_and_refund_erc721_maker_payment_timelock() { #[test] fn send_and_refund_erc1155_maker_payment_timelock() { - thread::sleep(Duration::from_secs(29)); let token_id = 2u32; let amount = 3u32; let time_lock_to_refund = now_sec() - 1000; + let activation = NftActivationV2Args::init(); let setup = setup_test( token_id, Some(amount), ContractType::Erc1155, - geth_nft_maker_swap_v2(), geth_erc1155_contract(), time_lock_to_refund, + activation, ); let maker_address = block_on(setup.maker_global_nft.my_addr()); @@ -1140,17 +1088,16 @@ fn send_and_refund_erc1155_maker_payment_timelock() { #[test] fn send_and_refund_erc721_maker_payment_secret() { - thread::sleep(Duration::from_secs(5)); let token_id = 3u32; let time_lock_to_refund = now_sec() + 1000; - + let activation = NftActivationV2Args::init(); let setup = setup_test( token_id, None, ContractType::Erc721, - geth_nft_maker_swap_v2(), geth_erc721_contract(), time_lock_to_refund, + activation, ); let maker_payment_to_refund = send_nft_maker_payment(&setup, 1.into()); @@ -1182,17 +1129,17 @@ fn send_and_refund_erc721_maker_payment_secret() { #[test] fn send_and_refund_erc1155_maker_payment_secret() { - thread::sleep(Duration::from_secs(2)); let token_id = 3u32; let amount = 3u32; let time_lock_to_refund = now_sec() + 1000; + let activation = NftActivationV2Args::init(); let setup = setup_test( token_id, Some(amount), ContractType::Erc1155, - geth_nft_maker_swap_v2(), geth_erc1155_contract(), time_lock_to_refund, + activation, ); let maker_address = block_on(setup.maker_global_nft.my_addr()); @@ -1252,14 +1199,37 @@ pub struct TestNftSwapInfo { /// Etomic swap contract address pub swap_contract_address: Coin::ContractAddress, } +struct NftActivationV2Args { + swap_contract_address: Address, + fallback_swap_contract_address: Address, + swap_v2_contracts: SwapV2Contracts, + nft_ticker: String, + platform_ticker: String, +} + +impl NftActivationV2Args { + fn init() -> Self { + Self { + swap_contract_address: swap_contract(), + fallback_swap_contract_address: swap_contract(), + swap_v2_contracts: SwapV2Contracts { + maker_swap_v2_contract: maker_swap_v2(), + taker_swap_v2_contract: taker_swap_v2(), + nft_maker_swap_v2_contract: geth_nft_maker_swap_v2(), + }, + nft_ticker: NFT_ETH.to_string(), + platform_ticker: "ETH".to_string(), + } + } +} fn setup_test( token_id: u32, amount: Option, contract_type: ContractType, - swap_contract_address: Address, token_contract: Address, time_lock: u64, + activation: NftActivationV2Args, ) -> NftTestSetup { let nft_type = match contract_type { ContractType::Erc721 => TestNftType::Erc721 { token_id }, @@ -1269,8 +1239,22 @@ fn setup_test( }, }; - let maker_global_nft = global_nft_with_random_privkey(swap_contract_address, Some(nft_type)); - let taker_global_nft = global_nft_with_random_privkey(swap_contract_address, None); + let maker_global_nft = global_nft_with_random_privkey( + activation.swap_v2_contracts, + activation.swap_contract_address, + activation.fallback_swap_contract_address, + Some(nft_type), + activation.nft_ticker.clone(), + activation.platform_ticker.clone(), + ); + let taker_global_nft = global_nft_with_random_privkey( + activation.swap_v2_contracts, + activation.swap_contract_address, + activation.fallback_swap_contract_address, + None, + activation.nft_ticker, + activation.platform_ticker, + ); let maker_secret = vec![1; 32]; let maker_secret_hash = sha256(&maker_secret).to_vec(); let taker_secret = vec![0; 32]; @@ -1282,7 +1266,7 @@ fn setup_test( token_address: token_contract, token_id, contract_type, - swap_contract_address, + swap_contract_address: activation.swap_v2_contracts.nft_maker_swap_v2_contract, }; NftTestSetup { @@ -1316,7 +1300,7 @@ fn send_nft_maker_payment(setup: &NftTestSetup, amount: BigDecimal) -> SignedEth block_on(setup.maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap() } -fn wait_for_confirmations(global_nft: &EthCoin, tx: &SignedEthTx, wait_seconds: u64) { +fn wait_for_confirmations(coin: &EthCoin, tx: &SignedEthTx, wait_seconds: u64) { let confirm_input = ConfirmPaymentInput { payment_tx: tx.tx_hex(), confirmations: 1, @@ -1324,7 +1308,7 @@ fn wait_for_confirmations(global_nft: &EthCoin, tx: &SignedEthTx, wait_seconds: wait_until: now_sec() + wait_seconds, check_every: 1, }; - global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + coin.wait_for_confirmations(confirm_input).wait().unwrap(); } fn validate_nft_maker_payment(setup: &NftTestSetup, maker_payment: &SignedEthTx, amount: BigDecimal) { @@ -1393,3 +1377,720 @@ enum RefundType { Timelock, Secret, } + +#[derive(Copy, Clone)] +struct SwapAddresses { + swap_v2_contracts: SwapV2Contracts, + swap_contract_address: Address, + fallback_swap_contract_address: Address, +} + +#[allow(dead_code)] +/// Needed for Geth taker or maker swap v2 tests +impl SwapAddresses { + fn init() -> Self { + Self { + swap_contract_address: swap_contract(), + fallback_swap_contract_address: swap_contract(), + swap_v2_contracts: SwapV2Contracts { + maker_swap_v2_contract: maker_swap_v2(), + taker_swap_v2_contract: taker_swap_v2(), + nft_maker_swap_v2_contract: geth_nft_maker_swap_v2(), + }, + } + } +} + +#[allow(dead_code)] +/// Needed for eth or erc20 v2 activation in Geth tests +fn eth_coin_v2_activation_with_random_privkey( + ticker: &str, + conf: &Json, + swap_addr: SwapAddresses, + erc20: bool, +) -> EthCoin { + let build_policy = EthPrivKeyBuildPolicy::IguanaPrivKey(random_secp256k1_secret()); + let node = EthNode { + url: GETH_RPC_URL.to_string(), + komodo_proxy: false, + }; + let platform_request = EthActivationV2Request { + nodes: vec![node], + rpc_mode: Default::default(), + swap_contract_address: swap_addr.swap_contract_address, + swap_v2_contracts: Some(swap_addr.swap_v2_contracts), + fallback_swap_contract: Some(swap_addr.fallback_swap_contract_address), + contract_supports_watchers: false, + mm2: None, + required_confirmations: None, + priv_key_policy: Default::default(), + enable_params: Default::default(), + path_to_address: Default::default(), + gap_limit: None, + }; + let coin = block_on(eth_coin_from_conf_and_request_v2( + &MM_CTX1, + ticker, + conf, + platform_request, + build_policy, + )) + .unwrap(); + let my_address = block_on(coin.my_addr()); + fill_eth(my_address, U256::from(10).pow(U256::from(20))); + fill_erc20(my_address, U256::from(10000000000u64)); + if erc20 { + let coin_type = EthCoinType::Erc20 { + platform: ETH.to_string(), + token_addr: erc20_contract(), + }; + let coin = block_on(coin.set_coin_type(coin_type)); + return coin; + } + coin +} + +#[ignore] +#[test] +fn send_and_refund_taker_funding_by_secret_eth() { + // sepolia test + thread::sleep(Duration::from_secs(5)); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let funding_time_lock = now_sec() + 3000; + let payment_time_lock = now_sec() + 1000; + + let taker_address = block_on(taker_coin.my_addr()); + + let dex_fee = &DexFee::Standard("0.00001".into()); + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let payment_args = SendTakerFundingArgs { + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_pub: maker_pub.as_bytes(), + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + thread::sleep(Duration::from_secs(2)); + let funding_tx = block_on(taker_coin.send_taker_funding(payment_args)).unwrap(); + log!("Taker sent ETH funding, tx hash: {:02x}", funding_tx.tx_hash()); + + let refund_args = RefundFundingSecretArgs { + funding_tx: &funding_tx, + funding_time_lock, + payment_time_lock, + maker_pubkey: maker_pub, + taker_secret: &taker_secret, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + dex_fee, + premium_amount: Default::default(), + trading_amount, + swap_unique_data: &[], + watcher_reward: false, + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx_refund = block_on(taker_coin.refund_taker_funding_secret(refund_args)).unwrap(); + log!( + "Taker refunded ETH funding by secret, tx hash: {:02x}", + funding_tx_refund.tx_hash() + ); + + wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); +} + +#[ignore] +#[test] +fn send_and_refund_taker_funding_by_secret_erc20() { + thread::sleep(Duration::from_secs(130)); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + + let taker_address = block_on(taker_coin.my_addr()); + + let funding_time_lock = now_sec() + 3000; + let payment_time_lock = now_sec() + 1000; + + let dex_fee = &DexFee::Standard("0.00001".into()); + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let payment_args = SendTakerFundingArgs { + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_pub: maker_pub.as_bytes(), + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx = block_on(taker_coin.send_taker_funding(payment_args)).unwrap(); + log!("Taker sent ERC20 funding, tx hash: {:02x}", funding_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &funding_tx, 200); + + let refund_args = RefundFundingSecretArgs { + funding_tx: &funding_tx, + funding_time_lock, + payment_time_lock, + maker_pubkey: &taker_coin.derive_htlc_pubkey_v2(&[]), + taker_secret: &taker_secret, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + dex_fee, + premium_amount: Default::default(), + trading_amount, + swap_unique_data: &[], + watcher_reward: false, + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx_refund = block_on(taker_coin.refund_taker_funding_secret(refund_args)).unwrap(); + log!( + "Taker refunded ERC20 funding by secret, tx hash: {:02x}", + funding_tx_refund.tx_hash() + ); + wait_for_confirmations(&taker_coin, &funding_tx_refund, 200); +} + +#[ignore] +#[test] +fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { + thread::sleep(Duration::from_secs(12)); + // sepolia test + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + + let taker_address = block_on(taker_coin.my_addr()); + + // if TakerPaymentState is `PaymentSent` then timestamp should exceed payment pre-approve lock time (funding_time_lock) + let funding_time_lock = now_sec() - 3000; + let payment_time_lock = now_sec() + 1000; + + let dex_fee = &DexFee::Standard("0.00001".into()); + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let payment_args = SendTakerFundingArgs { + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_pub: maker_pub.as_bytes(), + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx = block_on(taker_coin.send_taker_funding(payment_args)).unwrap(); + log!("Taker sent ETH funding, tx hash: {:02x}", funding_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &funding_tx, 100); + + let tx_type_with_secret_hash = SwapTxTypeWithSecretHash::TakerPaymentV2 { + maker_secret_hash: &maker_secret_hash, + taker_secret_hash: &taker_secret_hash, + }; + + let refund_args = RefundTakerPaymentArgs { + payment_tx: &funding_tx.to_bytes(), + time_lock: payment_time_lock, + maker_pub: maker_pub.as_bytes(), + tx_type_with_secret_hash, + swap_unique_data: &[], + watcher_reward: false, + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount, + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx_refund = block_on(taker_coin.refund_taker_funding_timelock(refund_args)).unwrap(); + log!( + "Taker refunded ETH funding after pre-approval lock time was exceeded, tx hash: {:02x}", + funding_tx_refund.tx_hash() + ); + + wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); +} + +#[ignore] +#[test] +fn taker_send_approve_and_spend_eth() { + // sepolia test + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let funding_time_lock = now_sec() + 3000; + let payment_time_lock = now_sec() + 600; + + let taker_address = block_on(taker_coin.my_addr()); + let maker_address = block_on(maker_coin.my_addr()); + + let dex_fee = &DexFee::Standard("0.00001".into()); + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let payment_args = SendTakerFundingArgs { + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_pub: maker_pub.as_bytes(), + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx = block_on(taker_coin.send_taker_funding(payment_args)).unwrap(); + log!("Taker sent ETH funding, tx hash: {:02x}", funding_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &funding_tx, 100); + + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + let validate = ValidateTakerFundingArgs { + funding_tx: &funding_tx, + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + taker_pub, + dex_fee, + premium_amount: Default::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + block_on(maker_coin.validate_taker_funding(validate)).unwrap(); + + let approve_args = GenTakerFundingSpendArgs { + funding_tx: &funding_tx, + maker_pub, + taker_pub, + funding_time_lock, + taker_secret_hash: &taker_secret_hash, + taker_payment_time_lock: funding_time_lock, + maker_secret_hash: &maker_secret_hash, + }; + let preimage = TxPreimageWithSig { + preimage: funding_tx.clone(), + signature: taker_coin.parse_signature(&[0u8; 65]).unwrap(), + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let taker_approve_tx = + block_on(taker_coin.sign_and_send_taker_funding_spend(&preimage, &approve_args, &[])).unwrap(); + log!( + "Taker approved ETH payment, tx hash: {:02x}", + taker_approve_tx.tx_hash() + ); + wait_for_confirmations(&taker_coin, &taker_approve_tx, 100); + + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let check_taker_approved_tx = block_on(maker_coin.search_for_taker_funding_spend(&taker_approve_tx, 0u64, &[])) + .unwrap() + .unwrap(); + match check_taker_approved_tx { + FundingTxSpend::TransferredToTakerPayment(tx) => { + assert_eq!(tx, taker_approve_tx); + }, + FundingTxSpend::RefundedTimelock(_) | FundingTxSpend::RefundedSecret { .. } => { + panic!("Wrong FundingTxSpend variant, expected TransferredToTakerPayment") + }, + }; + + let dex_fee_pub = sepolia_taker_swap_v2(); + let spend_args = GenTakerPaymentSpendArgs { + taker_tx: &taker_approve_tx, + time_lock: payment_time_lock, + maker_secret_hash: &maker_secret_hash, + maker_pub, + maker_address: &maker_address, + taker_pub, + dex_fee_pub: dex_fee_pub.as_bytes(), + dex_fee, + premium_amount: Default::default(), + trading_amount, + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let spend_tx = + block_on(maker_coin.sign_and_broadcast_taker_payment_spend(&preimage, &spend_args, &maker_secret, &[])) + .unwrap(); + log!("Maker spent ETH payment, tx hash: {:02x}", spend_tx.tx_hash()); + wait_for_confirmations(&maker_coin, &spend_tx, 100); + block_on(taker_coin.wait_for_taker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); +} + +#[ignore] +#[test] +fn taker_send_approve_and_spend_erc20() { + // sepolia test + thread::sleep(Duration::from_secs(9)); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let funding_time_lock = now_sec() + 3000; + let payment_time_lock = now_sec() + 600; + + let taker_address = block_on(taker_coin.my_addr()); + let maker_address = block_on(maker_coin.my_addr()); + + let dex_fee = &DexFee::Standard("0.00001".into()); + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let payment_args = SendTakerFundingArgs { + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_pub: maker_pub.as_bytes(), + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx = block_on(taker_coin.send_taker_funding(payment_args)).unwrap(); + log!("Taker sent ERC20 funding, tx hash: {:02x}", funding_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &funding_tx, 100); + + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + let validate = ValidateTakerFundingArgs { + funding_tx: &funding_tx, + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + taker_pub, + dex_fee, + premium_amount: Default::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + block_on(maker_coin.validate_taker_funding(validate)).unwrap(); + + let approve_args = GenTakerFundingSpendArgs { + funding_tx: &funding_tx, + maker_pub, + taker_pub, + funding_time_lock, + taker_secret_hash: &taker_secret_hash, + taker_payment_time_lock: funding_time_lock, + maker_secret_hash: &maker_secret_hash, + }; + let preimage = TxPreimageWithSig { + preimage: funding_tx.clone(), + signature: taker_coin.parse_signature(&[0u8; 65]).unwrap(), + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let taker_approve_tx = + block_on(taker_coin.sign_and_send_taker_funding_spend(&preimage, &approve_args, &[])).unwrap(); + log!( + "Taker approved ERC20 payment, tx hash: {:02x}", + taker_approve_tx.tx_hash() + ); + wait_for_confirmations(&taker_coin, &taker_approve_tx, 100); + + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let check_taker_approved_tx = block_on(maker_coin.search_for_taker_funding_spend(&taker_approve_tx, 0u64, &[])) + .unwrap() + .unwrap(); + match check_taker_approved_tx { + FundingTxSpend::TransferredToTakerPayment(tx) => { + assert_eq!(tx, taker_approve_tx); + }, + FundingTxSpend::RefundedTimelock(_) | FundingTxSpend::RefundedSecret { .. } => { + panic!("Wrong FundingTxSpend variant, expected TransferredToTakerPayment") + }, + }; + + let dex_fee_pub = sepolia_taker_swap_v2(); + let spend_args = GenTakerPaymentSpendArgs { + taker_tx: &taker_approve_tx, + time_lock: payment_time_lock, + maker_secret_hash: &maker_secret_hash, + maker_pub, + maker_address: &maker_address, + taker_pub, + dex_fee_pub: dex_fee_pub.as_bytes(), + dex_fee, + premium_amount: Default::default(), + trading_amount, + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let spend_tx = + block_on(maker_coin.sign_and_broadcast_taker_payment_spend(&preimage, &spend_args, &maker_secret, &[])) + .unwrap(); + log!("Maker spent ERC20 payment, tx hash: {:02x}", spend_tx.tx_hash()); + block_on(taker_coin.wait_for_taker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); +} + +#[ignore] +#[test] +fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { + // sepolia test + thread::sleep(Duration::from_secs(25)); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let funding_time_lock = now_sec() + 3000; + let payment_time_lock = now_sec() - 1000; + + let taker_address = block_on(taker_coin.my_addr()); + + let dex_fee = &DexFee::Standard("0.00001".into()); + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let payment_args = SendTakerFundingArgs { + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_pub: maker_pub.as_bytes(), + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx = block_on(taker_coin.send_taker_funding(payment_args)).unwrap(); + log!("Taker sent ETH funding, tx hash: {:02x}", funding_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &funding_tx, 100); + + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + let approve_args = GenTakerFundingSpendArgs { + funding_tx: &funding_tx, + maker_pub, + taker_pub, + funding_time_lock, + taker_secret_hash: &taker_secret_hash, + taker_payment_time_lock: funding_time_lock, + maker_secret_hash: &maker_secret_hash, + }; + let preimage = TxPreimageWithSig { + preimage: funding_tx.clone(), + signature: taker_coin.parse_signature(&[0u8; 65]).unwrap(), + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let taker_approve_tx = + block_on(taker_coin.sign_and_send_taker_funding_spend(&preimage, &approve_args, &[])).unwrap(); + log!( + "Taker approved ETH payment, tx hash: {:02x}", + taker_approve_tx.tx_hash() + ); + wait_for_confirmations(&taker_coin, &taker_approve_tx, 100); + + let tx_type_with_secret_hash = SwapTxTypeWithSecretHash::TakerPaymentV2 { + maker_secret_hash: &maker_secret_hash, + taker_secret_hash: &taker_secret_hash, + }; + let refund_args = RefundTakerPaymentArgs { + payment_tx: &funding_tx.to_bytes(), + time_lock: payment_time_lock, + maker_pub: maker_pub.as_bytes(), + tx_type_with_secret_hash, + swap_unique_data: &[], + watcher_reward: false, + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount, + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx_refund = block_on(taker_coin.refund_taker_funding_timelock(refund_args)).unwrap(); + log!( + "Taker refunded ETH funding after payment lock time was exceeded, tx hash: {:02x}", + funding_tx_refund.tx_hash() + ); + wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); +} + +#[ignore] +#[test] +fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { + // sepolia test + thread::sleep(Duration::from_secs(28)); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let funding_time_lock = now_sec() + 29; + let payment_time_lock = now_sec() + 15; + + let taker_address = block_on(taker_coin.my_addr()); + + let dex_fee = &DexFee::Standard("0.00001".into()); + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let payment_args = SendTakerFundingArgs { + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_pub: maker_pub.as_bytes(), + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx = block_on(taker_coin.send_taker_funding(payment_args)).unwrap(); + log!("Taker sent ERC20 funding, tx hash: {:02x}", funding_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &funding_tx, 100); + thread::sleep(Duration::from_secs(16)); + + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + let approve_args = GenTakerFundingSpendArgs { + funding_tx: &funding_tx, + maker_pub, + taker_pub, + funding_time_lock, + taker_secret_hash: &taker_secret_hash, + taker_payment_time_lock: funding_time_lock, + maker_secret_hash: &maker_secret_hash, + }; + let preimage = TxPreimageWithSig { + preimage: funding_tx.clone(), + signature: taker_coin.parse_signature(&[0u8; 65]).unwrap(), + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let taker_approve_tx = + block_on(taker_coin.sign_and_send_taker_funding_spend(&preimage, &approve_args, &[])).unwrap(); + log!( + "Taker approved ERC20 payment, tx hash: {:02x}", + taker_approve_tx.tx_hash() + ); + wait_for_confirmations(&taker_coin, &taker_approve_tx, 100); + + let tx_type_with_secret_hash = SwapTxTypeWithSecretHash::TakerPaymentV2 { + maker_secret_hash: &maker_secret_hash, + taker_secret_hash: &taker_secret_hash, + }; + let refund_args = RefundTakerPaymentArgs { + payment_tx: &funding_tx.to_bytes(), + time_lock: payment_time_lock, + maker_pub: maker_pub.as_bytes(), + tx_type_with_secret_hash, + swap_unique_data: &[], + watcher_reward: false, + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount, + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx_refund = block_on(taker_coin.refund_taker_funding_timelock(refund_args)).unwrap(); + log!( + "Taker refunded ERC20 funding after payment lock time was exceeded, tx hash: {:02x}", + funding_tx_refund.tx_hash() + ); + wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); +} + +#[ignore] +#[test] +fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { + // sepolia test + thread::sleep(Duration::from_secs(200)); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + + let taker_address = block_on(taker_coin.my_addr()); + + // if TakerPaymentState is `PaymentSent` then timestamp should exceed payment pre-approve lock time (funding_time_lock) + let funding_time_lock = now_sec() + 29; + let payment_time_lock = now_sec() + 1000; + + let dex_fee = &DexFee::Standard("0.00001".into()); + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let payment_args = SendTakerFundingArgs { + funding_time_lock, + payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_pub: maker_pub.as_bytes(), + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount: trading_amount.clone(), + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let funding_tx = block_on(taker_coin.send_taker_funding(payment_args)).unwrap(); + log!("Taker sent ERC20 funding, tx hash: {:02x}", funding_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &funding_tx, 150); + thread::sleep(Duration::from_secs(29)); + + let tx_type_with_secret_hash = SwapTxTypeWithSecretHash::TakerPaymentV2 { + maker_secret_hash: &maker_secret_hash, + taker_secret_hash: &taker_secret_hash, + }; + + let refund_args = RefundTakerPaymentArgs { + payment_tx: &funding_tx.to_bytes(), + time_lock: payment_time_lock, + maker_pub: maker_pub.as_bytes(), + tx_type_with_secret_hash, + swap_unique_data: &[], + watcher_reward: false, + dex_fee, + premium_amount: BigDecimal::default(), + trading_amount, + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + thread::sleep(Duration::from_secs(3)); + let funding_tx_refund = block_on(taker_coin.refund_taker_funding_timelock(refund_args)).unwrap(); + log!( + "Taker refunded ERC20 funding after pre-approval lock time was exceeded, tx hash: {:02x}", + funding_tx_refund.tx_hash() + ); + wait_for_confirmations(&taker_coin, &funding_tx_refund, 150); +} diff --git a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs index f6491dcef7..672ef88aa5 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs @@ -2,9 +2,10 @@ use crate::{generate_utxo_coin_with_random_privkey, MYCOIN, MYCOIN1}; use bitcrypto::dhash160; use coins::utxo::UtxoCommonOps; use coins::{ConfirmPaymentInput, DexFee, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, - MakerCoinSwapOpsV2, MarketCoinOps, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundMakerPaymentArgs, - RefundPaymentArgs, SendMakerPaymentArgs, SendTakerFundingArgs, SwapTxTypeWithSecretHash, - TakerCoinSwapOpsV2, Transaction, ValidateMakerPaymentArgs, ValidateTakerFundingArgs}; + MakerCoinSwapOpsV2, MarketCoinOps, ParseCoinAssocTypes, RefundFundingSecretArgs, + RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, RefundTakerPaymentArgs, + SendMakerPaymentArgs, SendTakerFundingArgs, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, Transaction, + ValidateMakerPaymentArgs, ValidateTakerFundingArgs}; use common::{block_on, now_sec, DEX_FEE_ADDR_RAW_PUBKEY}; use futures01::Future; use mm2_number::MmNumber; @@ -55,9 +56,11 @@ fn send_and_refund_taker_funding_timelock() { let validate_args = ValidateTakerFundingArgs { funding_tx: &taker_funding_utxo_tx, - time_lock: funding_time_lock, + payment_time_lock: 0, + funding_time_lock, taker_secret_hash, - other_pub: maker_pub, + maker_secret_hash: &[], + taker_pub: maker_pub, dex_fee, premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), @@ -65,16 +68,18 @@ fn send_and_refund_taker_funding_timelock() { }; block_on(coin.validate_taker_funding(validate_args)).unwrap(); - let refund_args = RefundPaymentArgs { + let refund_args = RefundTakerPaymentArgs { payment_tx: &serialize(&taker_funding_utxo_tx).take(), time_lock: funding_time_lock, - other_pubkey: coin.my_public_key().unwrap(), + maker_pub: coin.my_public_key().unwrap(), tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerFunding { taker_secret_hash: &[0; 20], }, swap_unique_data: &[], - swap_contract_address: &None, watcher_reward: false, + dex_fee, + premium_amount: Default::default(), + trading_amount: Default::default(), }; let refund_tx = block_on(coin.refund_taker_funding_timelock(refund_args)).unwrap(); @@ -137,9 +142,11 @@ fn send_and_refund_taker_funding_secret() { let validate_args = ValidateTakerFundingArgs { funding_tx: &taker_funding_utxo_tx, - time_lock: funding_time_lock, + funding_time_lock, + payment_time_lock: 0, taker_secret_hash, - other_pub: maker_pub, + maker_secret_hash: &[], + taker_pub: maker_pub, dex_fee, premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), @@ -155,7 +162,6 @@ fn send_and_refund_taker_funding_secret() { taker_secret: &taker_secret, taker_secret_hash, maker_secret_hash: &[], - swap_contract_address: &None, dex_fee, premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), @@ -228,9 +234,11 @@ fn send_and_spend_taker_funding() { let validate_args = ValidateTakerFundingArgs { funding_tx: &taker_funding_utxo_tx, - time_lock: funding_time_lock, + payment_time_lock: 0, + funding_time_lock, taker_secret_hash, - other_pub: taker_pub, + maker_secret_hash: &[], + taker_pub, dex_fee, premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), @@ -317,9 +325,11 @@ fn send_and_spend_taker_payment_dex_fee_burn() { let validate_args = ValidateTakerFundingArgs { funding_tx: &taker_funding_utxo_tx, - time_lock: funding_time_lock, + funding_time_lock, + payment_time_lock: 0, taker_secret_hash, - other_pub: taker_pub, + maker_secret_hash, + taker_pub, dex_fee, premium_amount: 0.into(), trading_amount: 777.into(), @@ -422,9 +432,11 @@ fn send_and_spend_taker_payment_standard_dex_fee() { let validate_args = ValidateTakerFundingArgs { funding_tx: &taker_funding_utxo_tx, - time_lock: funding_time_lock, + funding_time_lock, + payment_time_lock: 0, taker_secret_hash, - other_pub: taker_pub, + maker_secret_hash, + taker_pub, dex_fee, premium_amount: 0.into(), trading_amount: 777.into(), @@ -528,10 +540,10 @@ fn send_and_refund_maker_payment_timelock() { }; block_on(coin.validate_maker_payment_v2(validate_args)).unwrap(); - let refund_args = RefundPaymentArgs { + let refund_args = RefundMakerPaymentTimelockArgs { payment_tx: &serialize(&maker_payment).take(), time_lock, - other_pubkey: coin.my_public_key().unwrap(), + taker_pub: coin.my_public_key().unwrap(), tx_type_with_secret_hash: SwapTxTypeWithSecretHash::MakerPaymentV2 { taker_secret_hash, maker_secret_hash, @@ -592,7 +604,7 @@ fn send_and_refund_maker_payment_taker_secret() { }; block_on(coin.validate_maker_payment_v2(validate_args)).unwrap(); - let refund_args = RefundMakerPaymentArgs { + let refund_args = RefundMakerPaymentSecretArgs { maker_payment_tx: &maker_payment, time_lock, taker_secret_hash, diff --git a/mm2src/mm2_test_helpers/contract_bytes/maker_swap_v2_bytes b/mm2src/mm2_test_helpers/contract_bytes/maker_swap_v2_bytes index 5b8bda7350..5ac667f370 100644 --- a/mm2src/mm2_test_helpers/contract_bytes/maker_swap_v2_bytes +++ b/mm2src/mm2_test_helpers/contract_bytes/maker_swap_v2_bytes @@ -1 +1 @@ -6080604052348015600e575f80fd5b50611d9f8061001c5f395ff3fe608060405260043610610054575f3560e01c80631299a27a146100585780637466be601461008057806374a4788a1461009c5780639b949dee146100c4578063a53bc126146100ec578063efccb9eb14610114575b5f80fd5b348015610063575f80fd5b5061007e60048036038101906100799190611427565b610152565b005b61009a600480360381019061009591906114e9565b61044b565b005b3480156100a7575f80fd5b506100c260048036038101906100bd9190611427565b6106fc565b005b3480156100cf575f80fd5b506100ea60048036038101906100e59190611427565b6109f5565b005b3480156100f7575f80fd5b50610112600480360381019061010d9190611560565b610ced565b005b34801561011f575f80fd5b5061013a600480360381019061013591906115fd565b610fd2565b604051610149939291906116e4565b60405180910390f35b6001600381111561016657610165611671565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561019857610197611671565b5b146101d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101cf90611799565b60405180910390fd5b5f6003863387876002886040516020016101f291906117d7565b60405160208183030381529060405260405161020e9190611843565b602060405180830381855afa158015610229573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061024c919061186d565b87604051602001610262969594939291906118fd565b60405160208183030381529060405260405161027e9190611843565b602060405180830381855afa158015610299573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610323576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031a906119b6565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561035957610358611671565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161038d91906119e3565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610411573373ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f1935050505015801561040b573d5f803e3d5ffd5b50610442565b5f82905061044033888373ffffffffffffffffffffffffffffffffffffffff1661101e9092919063ffffffff16565b505b50505050505050565b5f600381111561045e5761045d611671565b5b5f808781526020019081526020015f205f0160189054906101000a900460ff1660038111156104905761048f611671565b5b146104d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c790611a6c565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361053e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053590611ad4565b60405180910390fd5b5f3411610580576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057790611b62565b60405180910390fd5b5f600334863387875f60405160200161059e969594939291906118fd565b6040516020818303038152906040526040516105ba9190611843565b602060405180830381855afa1580156105d5573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018363ffffffff1681526020016001600381111561062157610620611671565b5b8152505f808881526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156106b5576106b4611671565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad866040516106ec91906119e3565b60405180910390a1505050505050565b600160038111156107105761070f611671565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561074257610741611671565b5b14610782576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161077990611799565b60405180910390fd5b5f600386863360028860405160200161079b91906117d7565b6040516020818303038152906040526040516107b79190611843565b602060405180830381855afa1580156107d2573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906107f5919061186d565b878760405160200161080c969594939291906118fd565b6040516020818303038152906040526040516108289190611843565b602060405180830381855afa158015610843573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146108cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108c4906119b6565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561090357610902611671565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd738760405161093791906119e3565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036109bb573373ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f193505050501580156109b5573d5f803e3d5ffd5b506109ec565b5f8290506109ea33888373ffffffffffffffffffffffffffffffffffffffff1661101e9092919063ffffffff16565b505b50505050505050565b60016003811115610a0957610a08611671565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff166003811115610a3b57610a3a611671565b5b14610a7b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a7290611799565b60405180910390fd5b5f6003868633878787604051602001610a99969594939291906118fd565b604051602081830303815290604052604051610ab59190611843565b602060405180830381855afa158015610ad0573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610b5a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b51906119b6565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610bc5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbc90611bf0565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610bfb57610bfa611671565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad1921907287604051610c2f91906119e3565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610cb3573373ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015610cad573d5f803e3d5ffd5b50610ce4565b5f829050610ce233888373ffffffffffffffffffffffffffffffffffffffff1661101e9092919063ffffffff16565b505b50505050505050565b5f6003811115610d0057610cff611671565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610d3257610d31611671565b5b14610d72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6990611a6c565b60405180910390fd5b5f8611610db4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dab90611c58565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610e22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e1990611ad4565b60405180910390fd5b5f600387863387878b604051602001610e40969594939291906118fd565b604051602081830303815290604052604051610e5c9190611843565b602060405180830381855afa158015610e77573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018363ffffffff16815260200160016003811115610ec357610ec2611671565b5b8152505f808a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610f5757610f56611671565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad88604051610f8e91906119e3565b60405180910390a15f869050610fc733308a8473ffffffffffffffffffffffffffffffffffffffff1661109d909392919063ffffffff16565b505050505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b611098838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8585604051602401611051929190611c94565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061111f565b505050565b611119848573ffffffffffffffffffffffffffffffffffffffff166323b872dd8686866040516024016110d293929190611cbb565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061111f565b50505050565b5f611149828473ffffffffffffffffffffffffffffffffffffffff166111b490919063ffffffff16565b90505f81511415801561116d57508080602001905181019061116b9190611d25565b155b156111af57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016111a69190611d50565b60405180910390fd5b505050565b60606111c183835f6111c9565b905092915050565b60608147101561121057306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016112079190611d50565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516112389190611843565b5f6040518083038185875af1925050503d805f8114611272576040519150601f19603f3d011682016040523d82523d5f602084013e611277565b606091505b5091509150611287868383611292565b925050509392505050565b6060826112a7576112a28261131f565b611317565b5f82511480156112cd57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561130f57836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016113069190611d50565b60405180910390fd5b819050611318565b5b9392505050565b5f815111156113315780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80fd5b5f819050919050565b61137981611367565b8114611383575f80fd5b50565b5f8135905061139481611370565b92915050565b5f819050919050565b6113ac8161139a565b81146113b6575f80fd5b50565b5f813590506113c7816113a3565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6113f6826113cd565b9050919050565b611406816113ec565b8114611410575f80fd5b50565b5f81359050611421816113fd565b92915050565b5f805f805f8060c0878903121561144157611440611363565b5b5f61144e89828a01611386565b965050602061145f89828a016113b9565b955050604061147089828a01611413565b945050606061148189828a01611386565b935050608061149289828a01611386565b92505060a06114a389828a01611413565b9150509295509295509295565b5f63ffffffff82169050919050565b6114c8816114b0565b81146114d2575f80fd5b50565b5f813590506114e3816114bf565b92915050565b5f805f805f60a0868803121561150257611501611363565b5b5f61150f88828901611386565b955050602061152088828901611413565b945050604061153188828901611386565b935050606061154288828901611386565b9250506080611553888289016114d5565b9150509295509295909350565b5f805f805f805f60e0888a03121561157b5761157a611363565b5b5f6115888a828b01611386565b97505060206115998a828b016113b9565b96505060406115aa8a828b01611413565b95505060606115bb8a828b01611413565b94505060806115cc8a828b01611386565b93505060a06115dd8a828b01611386565b92505060c06115ee8a828b016114d5565b91505092959891949750929550565b5f6020828403121561161257611611611363565b5b5f61161f84828501611386565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b61165c81611628565b82525050565b61166b816114b0565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600481106116af576116ae611671565b5b50565b5f8190506116bf8261169e565b919050565b5f6116ce826116b2565b9050919050565b6116de816116c4565b82525050565b5f6060820190506116f75f830186611653565b6117046020830185611662565b61171160408301846116d5565b949350505050565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f611783602a83611719565b915061178e82611729565b604082019050919050565b5f6020820190508181035f8301526117b081611777565b9050919050565b5f819050919050565b6117d16117cc82611367565b6117b7565b82525050565b5f6117e282846117c0565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f61181d826117f1565b61182781856117fb565b9350611837818560208601611805565b80840191505092915050565b5f61184e8284611813565b915081905092915050565b5f8151905061186781611370565b92915050565b5f6020828403121561188257611881611363565b5b5f61188f84828501611859565b91505092915050565b5f819050919050565b6118b26118ad8261139a565b611898565b82525050565b5f8160601b9050919050565b5f6118ce826118b8565b9050919050565b5f6118df826118c4565b9050919050565b6118f76118f2826113ec565b6118d5565b82525050565b5f61190882896118a1565b60208201915061191882886118e6565b60148201915061192882876118e6565b60148201915061193882866117c0565b60208201915061194882856117c0565b60208201915061195882846118e6565b601482019150819050979650505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f6119a0601383611719565b91506119ab8261196c565b602082019050919050565b5f6020820190508181035f8301526119cd81611994565b9050919050565b6119dd81611367565b82525050565b5f6020820190506119f65f8301846119d4565b92915050565b7f4d616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f611a56602483611719565b9150611a61826119fc565b604082019050919050565b5f6020820190508181035f830152611a8381611a4a565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f611abe601e83611719565b9150611ac982611a8a565b602082019050919050565b5f6020820190508181035f830152611aeb81611ab2565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f611b4c602383611719565b9150611b5782611af2565b604082019050919050565b5f6020820190508181035f830152611b7981611b40565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f611bda603883611719565b9150611be582611b80565b604082019050919050565b5f6020820190508181035f830152611c0781611bce565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f611c42601783611719565b9150611c4d82611c0e565b602082019050919050565b5f6020820190508181035f830152611c6f81611c36565b9050919050565b611c7f816113ec565b82525050565b611c8e8161139a565b82525050565b5f604082019050611ca75f830185611c76565b611cb46020830184611c85565b9392505050565b5f606082019050611cce5f830186611c76565b611cdb6020830185611c76565b611ce86040830184611c85565b949350505050565b5f8115159050919050565b611d0481611cf0565b8114611d0e575f80fd5b50565b5f81519050611d1f81611cfb565b92915050565b5f60208284031215611d3a57611d39611363565b5b5f611d4784828501611d11565b91505092915050565b5f602082019050611d635f830184611c76565b9291505056fea2646970667358221220565f86096f083c176a08cc3c220c01bd63eb7268584f034f3380299de3dac57f64736f6c63430008190033 \ No newline at end of file +6080604052348015600e575f80fd5b50611d9f8061001c5f395ff3fe608060405260043610610054575f3560e01c80631299a27a146100585780637466be601461008057806374a4788a1461009c5780639b949dee146100c4578063a53bc126146100ec578063efccb9eb14610114575b5f80fd5b348015610063575f80fd5b5061007e60048036038101906100799190611427565b610152565b005b61009a600480360381019061009591906114e9565b61044b565b005b3480156100a7575f80fd5b506100c260048036038101906100bd9190611427565b6106fc565b005b3480156100cf575f80fd5b506100ea60048036038101906100e59190611427565b6109f5565b005b3480156100f7575f80fd5b50610112600480360381019061010d9190611560565b610ced565b005b34801561011f575f80fd5b5061013a600480360381019061013591906115fd565b610fd2565b604051610149939291906116e4565b60405180910390f35b6001600381111561016657610165611671565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561019857610197611671565b5b146101d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101cf90611799565b60405180910390fd5b5f6003863387876002886040516020016101f291906117d7565b60405160208183030381529060405260405161020e9190611843565b602060405180830381855afa158015610229573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061024c919061186d565b87604051602001610262969594939291906118fd565b60405160208183030381529060405260405161027e9190611843565b602060405180830381855afa158015610299573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610323576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031a906119b6565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561035957610358611671565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161038d91906119e3565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610411573373ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f1935050505015801561040b573d5f803e3d5ffd5b50610442565b5f82905061044033888373ffffffffffffffffffffffffffffffffffffffff1661101e9092919063ffffffff16565b505b50505050505050565b5f600381111561045e5761045d611671565b5b5f808781526020019081526020015f205f0160189054906101000a900460ff1660038111156104905761048f611671565b5b146104d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c790611a6c565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361053e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053590611ad4565b60405180910390fd5b5f3411610580576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057790611b62565b60405180910390fd5b5f600334863387875f60405160200161059e969594939291906118fd565b6040516020818303038152906040526040516105ba9190611843565b602060405180830381855afa1580156105d5573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018363ffffffff1681526020016001600381111561062157610620611671565b5b8152505f808881526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156106b5576106b4611671565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad866040516106ec91906119e3565b60405180910390a1505050505050565b600160038111156107105761070f611671565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561074257610741611671565b5b14610782576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161077990611799565b60405180910390fd5b5f600386863360028860405160200161079b91906117d7565b6040516020818303038152906040526040516107b79190611843565b602060405180830381855afa1580156107d2573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906107f5919061186d565b878760405160200161080c969594939291906118fd565b6040516020818303038152906040526040516108289190611843565b602060405180830381855afa158015610843573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146108cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108c4906119b6565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561090357610902611671565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd738760405161093791906119e3565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036109bb573373ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f193505050501580156109b5573d5f803e3d5ffd5b506109ec565b5f8290506109ea33888373ffffffffffffffffffffffffffffffffffffffff1661101e9092919063ffffffff16565b505b50505050505050565b60016003811115610a0957610a08611671565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff166003811115610a3b57610a3a611671565b5b14610a7b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a7290611799565b60405180910390fd5b5f6003868633878787604051602001610a99969594939291906118fd565b604051602081830303815290604052604051610ab59190611843565b602060405180830381855afa158015610ad0573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610b5a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b51906119b6565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610bc5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbc90611bf0565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610bfb57610bfa611671565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad1921907287604051610c2f91906119e3565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610cb3573373ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015610cad573d5f803e3d5ffd5b50610ce4565b5f829050610ce233888373ffffffffffffffffffffffffffffffffffffffff1661101e9092919063ffffffff16565b505b50505050505050565b5f6003811115610d0057610cff611671565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610d3257610d31611671565b5b14610d72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6990611a6c565b60405180910390fd5b5f8611610db4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dab90611c58565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610e22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e1990611ad4565b60405180910390fd5b5f600387863387878b604051602001610e40969594939291906118fd565b604051602081830303815290604052604051610e5c9190611843565b602060405180830381855afa158015610e77573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018363ffffffff16815260200160016003811115610ec357610ec2611671565b5b8152505f808a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610f5757610f56611671565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad88604051610f8e91906119e3565b60405180910390a15f869050610fc733308a8473ffffffffffffffffffffffffffffffffffffffff1661109d909392919063ffffffff16565b505050505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b611098838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8585604051602401611051929190611c94565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061111f565b505050565b611119848573ffffffffffffffffffffffffffffffffffffffff166323b872dd8686866040516024016110d293929190611cbb565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061111f565b50505050565b5f611149828473ffffffffffffffffffffffffffffffffffffffff166111b490919063ffffffff16565b90505f81511415801561116d57508080602001905181019061116b9190611d25565b155b156111af57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016111a69190611d50565b60405180910390fd5b505050565b60606111c183835f6111c9565b905092915050565b60608147101561121057306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016112079190611d50565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516112389190611843565b5f6040518083038185875af1925050503d805f8114611272576040519150601f19603f3d011682016040523d82523d5f602084013e611277565b606091505b5091509150611287868383611292565b925050509392505050565b6060826112a7576112a28261131f565b611317565b5f82511480156112cd57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561130f57836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016113069190611d50565b60405180910390fd5b819050611318565b5b9392505050565b5f815111156113315780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80fd5b5f819050919050565b61137981611367565b8114611383575f80fd5b50565b5f8135905061139481611370565b92915050565b5f819050919050565b6113ac8161139a565b81146113b6575f80fd5b50565b5f813590506113c7816113a3565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6113f6826113cd565b9050919050565b611406816113ec565b8114611410575f80fd5b50565b5f81359050611421816113fd565b92915050565b5f805f805f8060c0878903121561144157611440611363565b5b5f61144e89828a01611386565b965050602061145f89828a016113b9565b955050604061147089828a01611413565b945050606061148189828a01611386565b935050608061149289828a01611386565b92505060a06114a389828a01611413565b9150509295509295509295565b5f63ffffffff82169050919050565b6114c8816114b0565b81146114d2575f80fd5b50565b5f813590506114e3816114bf565b92915050565b5f805f805f60a0868803121561150257611501611363565b5b5f61150f88828901611386565b955050602061152088828901611413565b945050604061153188828901611386565b935050606061154288828901611386565b9250506080611553888289016114d5565b9150509295509295909350565b5f805f805f805f60e0888a03121561157b5761157a611363565b5b5f6115888a828b01611386565b97505060206115998a828b016113b9565b96505060406115aa8a828b01611413565b95505060606115bb8a828b01611413565b94505060806115cc8a828b01611386565b93505060a06115dd8a828b01611386565b92505060c06115ee8a828b016114d5565b91505092959891949750929550565b5f6020828403121561161257611611611363565b5b5f61161f84828501611386565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b61165c81611628565b82525050565b61166b816114b0565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600481106116af576116ae611671565b5b50565b5f8190506116bf8261169e565b919050565b5f6116ce826116b2565b9050919050565b6116de816116c4565b82525050565b5f6060820190506116f75f830186611653565b6117046020830185611662565b61171160408301846116d5565b949350505050565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f611783602a83611719565b915061178e82611729565b604082019050919050565b5f6020820190508181035f8301526117b081611777565b9050919050565b5f819050919050565b6117d16117cc82611367565b6117b7565b82525050565b5f6117e282846117c0565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f61181d826117f1565b61182781856117fb565b9350611837818560208601611805565b80840191505092915050565b5f61184e8284611813565b915081905092915050565b5f8151905061186781611370565b92915050565b5f6020828403121561188257611881611363565b5b5f61188f84828501611859565b91505092915050565b5f819050919050565b6118b26118ad8261139a565b611898565b82525050565b5f8160601b9050919050565b5f6118ce826118b8565b9050919050565b5f6118df826118c4565b9050919050565b6118f76118f2826113ec565b6118d5565b82525050565b5f61190882896118a1565b60208201915061191882886118e6565b60148201915061192882876118e6565b60148201915061193882866117c0565b60208201915061194882856117c0565b60208201915061195882846118e6565b601482019150819050979650505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f6119a0601383611719565b91506119ab8261196c565b602082019050919050565b5f6020820190508181035f8301526119cd81611994565b9050919050565b6119dd81611367565b82525050565b5f6020820190506119f65f8301846119d4565b92915050565b7f4d616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f611a56602483611719565b9150611a61826119fc565b604082019050919050565b5f6020820190508181035f830152611a8381611a4a565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f611abe601e83611719565b9150611ac982611a8a565b602082019050919050565b5f6020820190508181035f830152611aeb81611ab2565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f611b4c602383611719565b9150611b5782611af2565b604082019050919050565b5f6020820190508181035f830152611b7981611b40565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f611bda603883611719565b9150611be582611b80565b604082019050919050565b5f6020820190508181035f830152611c0781611bce565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f611c42601783611719565b9150611c4d82611c0e565b602082019050919050565b5f6020820190508181035f830152611c6f81611c36565b9050919050565b611c7f816113ec565b82525050565b611c8e8161139a565b82525050565b5f604082019050611ca75f830185611c76565b611cb46020830184611c85565b9392505050565b5f606082019050611cce5f830186611c76565b611cdb6020830185611c76565b611ce86040830184611c85565b949350505050565b5f8115159050919050565b611d0481611cf0565b8114611d0e575f80fd5b50565b5f81519050611d1f81611cfb565b92915050565b5f60208284031215611d3a57611d39611363565b5b5f611d4784828501611d11565b91505092915050565b5f602082019050611d635f830184611c76565b9291505056fea26469706673582212200d7b67fe7b5e6829da1f56f14431b4ee61dc3a66fb17a79f0587fda0329d09ba64736f6c634300081a0033 \ No newline at end of file diff --git a/mm2src/mm2_test_helpers/contract_bytes/nft_maker_swap_v2_bytes b/mm2src/mm2_test_helpers/contract_bytes/nft_maker_swap_v2_bytes index 93922e9594..ea4cd8c817 100644 --- a/mm2src/mm2_test_helpers/contract_bytes/nft_maker_swap_v2_bytes +++ b/mm2src/mm2_test_helpers/contract_bytes/nft_maker_swap_v2_bytes @@ -1 +1 @@ -6080604052348015600e575f80fd5b506131fa8061001c5f395ff3fe608060405234801561000f575f80fd5b50600436106100cd575f3560e01c8063bc197c811161008a578063eb4ab61211610064578063eb4ab61214610209578063efccb9eb14610225578063f0e9fcd114610257578063f23a6e6114610273576100cd565b8063bc197c81146101a1578063c8d9009b146101d1578063c92cd12d146101ed576100cd565b806301ffc9a7146100d157806305ec158d146101015780630f235fce1461011d578063150b7a02146101395780636e6bf6d214610169578063b27e46fb14610185575b5f80fd5b6100eb60048036038101906100e69190612005565b6102a3565b6040516100f8919061204a565b60405180910390f35b61011b60048036038101906101169190612123565b610384565b005b610137600480360381019061013291906121c0565b610644565b005b610153600480360381019061014e91906122aa565b6108fe565b604051610160919061233d565b60405180910390f35b610183600480360381019061017e91906121c0565b610d4d565b005b61019f600480360381019061019a9190612123565b611008565b005b6101bb60048036038101906101b691906123ab565b6112c7565b6040516101c8919061233d565b60405180910390f35b6101eb60048036038101906101e691906121c0565b611303565b005b61020760048036038101906102029190612123565b61162c565b005b610223600480360381019061021e9190612482565b61195a565b005b61023f600480360381019061023a91906124e6565b6119d1565b60405161024e939291906125dc565b60405180910390f35b610271600480360381019061026c9190612611565b611a1d565b005b61028d60048036038101906102889190612661565b611a91565b60405161029a919061233d565b60405180910390f35b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061036d57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061037d575061037c82611f25565b5b9050919050565b6001600381111561039857610397612569565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff1660038111156103ca576103c9612569565b5b1461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161040190612777565b60405180910390fd5b5f6003873360028960405160200161042291906127b5565b60405160208183030381529060405260405161043e9190612821565b602060405180830381855afa158015610459573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061047c919061284b565b8888888860405160200161049697969594939291906128db565b6040516020818303038152906040526040516104b29190612821565b602060405180830381855afa1580156104cd573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161054e906129a5565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561058d5761058c612569565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd73886040516105c191906129d2565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b815260040161060c9493929190612a3c565b5f604051808303815f87803b158015610623575f80fd5b505af1158015610635573d5f803e3d5ffd5b50505050505050505050505050565b6001600381111561065857610657612569565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561068a57610689612569565b5b146106ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c190612777565b60405180910390fd5b5f60038633878787876040516020016106e896959493929190612a92565b6040516020818303038152906040526040516107049190612821565b602060405180830381855afa15801561071f573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146107a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107a0906129a5565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610814576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161080b90612b71565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561084a57610849612569565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728760405161087e91906129d2565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016108c793929190612b8f565b5f604051808303815f87803b1580156108de575f80fd5b505af11580156108f0573d5f803e3d5ffd5b505050505050505050505050565b5f80838381019061090f9190612d17565b90505f600381111561092457610923612569565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff16600381111561095957610958612569565b5b14610999576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099090612db2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610a0b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0290612e1a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610a7d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a7490612e82565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ae690612f10565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610b5d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5490612f78565b60405180910390fd5b610b6a8160200151611f8e565b15610baa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ba190612fe0565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610bd896959493929190612a92565b604051602081830303815290604052604051610bf49190612821565b602060405180830381855afa158015610c0f573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610c5f57610c5e612569565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610cf657610cf5612569565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610d3091906129d2565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610d6157610d60612569565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff166003811115610d9357610d92612569565b5b14610dd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dca90612777565b60405180910390fd5b5f60038633600288604051602001610deb91906127b5565b604051602081830303815290604052604051610e079190612821565b602060405180830381855afa158015610e22573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190610e45919061284b565b878787604051602001610e5d96959493929190612a92565b604051602081830303815290604052604051610e799190612821565b602060405180830381855afa158015610e94573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610f1e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f15906129a5565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610f5457610f53612569565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051610f8891906129d2565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401610fd193929190612b8f565b5f604051808303815f87803b158015610fe8575f80fd5b505af1158015610ffa573d5f803e3d5ffd5b505050505050505050505050565b6001600381111561101c5761101b612569565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561104e5761104d612569565b5b1461108e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161108590612777565b60405180910390fd5b5f6003873388888888886040516020016110ae97969594939291906128db565b6040516020818303038152906040526040516110ca9190612821565b602060405180830381855afa1580156110e5573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461116f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611166906129a5565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156111da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111d190612b71565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156112105761120f612569565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728860405161124491906129d2565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b815260040161128f9493929190612a3c565b5f604051808303815f87803b1580156112a6575f80fd5b505af11580156112b8573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112fa90613048565b60405180910390fd5b6001600381111561131757611316612569565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561134957611348612569565b5b14611389576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161138090612777565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146113f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113ee906130b0565b60405180910390fd5b5f600333878760028860405160200161141091906127b5565b60405160208183030381529060405260405161142c9190612821565b602060405180830381855afa158015611447573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061146a919061284b565b878760405160200161148196959493929190612a92565b60405160208183030381529060405260405161149d9190612821565b602060405180830381855afa1580156114b8573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611542576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611539906129a5565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561157857611577612569565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0876040516115ac91906129d2565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016115f593929190612b8f565b5f604051808303815f87803b15801561160c575f80fd5b505af115801561161e573d5f803e3d5ffd5b505050505050505050505050565b600160038111156116405761163f612569565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561167257611671612569565b5b146116b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116a990612777565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611720576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611717906130b0565b60405180910390fd5b5f600333888860028960405160200161173991906127b5565b6040516020818303038152906040526040516117559190612821565b602060405180830381855afa158015611770573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611793919061284b565b8888886040516020016117ac97969594939291906128db565b6040516020818303038152906040526040516117c89190612821565b602060405180830381855afa1580156117e3573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461186d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611864906129a5565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156118a3576118a2612569565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0886040516118d791906129d2565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016119229493929190612a3c565b5f604051808303815f87803b158015611939575f80fd5b505af115801561194b573d5f803e3d5ffd5b50505050505050505050505050565b5f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a308487876040518563ffffffff1660e01b815260040161199d9493929190612a3c565b5f604051808303815f87803b1580156119b4575f80fd5b505af11580156119c6573d5f803e3d5ffd5b505050505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3084866040518463ffffffff1660e01b8152600401611a5e93929190612b8f565b5f604051808303815f87803b158015611a75575f80fd5b505af1158015611a87573d5f803e3d5ffd5b5050505050505050565b5f808383810190611aa29190612d17565b90505f6003811115611ab757611ab6612569565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115611aec57611aeb612569565b5b14611b2c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b239061313e565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603611b9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9590612e1a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603611c10576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c0790612e82565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c82576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c7990612f10565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614611cf0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ce790612f78565b60405180910390fd5b5f8511611d32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d29906131a6565b60405180910390fd5b611d3f8160200151611f8e565b15611d7f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d7690612fe0565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001611daf97969594939291906128db565b604051602081830303815290604052604051611dcb9190612821565b602060405180830381855afa158015611de6573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115611e3657611e35612569565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115611ecd57611ecc612569565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051611f0791906129d2565b60405180910390a163f23a6e6160e01b925050509695505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611fe481611fb0565b8114611fee575f80fd5b50565b5f81359050611fff81611fdb565b92915050565b5f6020828403121561201a57612019611fa8565b5b5f61202784828501611ff1565b91505092915050565b5f8115159050919050565b61204481612030565b82525050565b5f60208201905061205d5f83018461203b565b92915050565b5f819050919050565b61207581612063565b811461207f575f80fd5b50565b5f813590506120908161206c565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6120bf82612096565b9050919050565b6120cf816120b5565b81146120d9575f80fd5b50565b5f813590506120ea816120c6565b92915050565b5f819050919050565b612102816120f0565b811461210c575f80fd5b50565b5f8135905061211d816120f9565b92915050565b5f805f805f805f60e0888a03121561213e5761213d611fa8565b5b5f61214b8a828b01612082565b975050602061215c8a828b016120dc565b965050604061216d8a828b01612082565b955050606061217e8a828b01612082565b945050608061218f8a828b016120dc565b93505060a06121a08a828b0161210f565b92505060c06121b18a828b0161210f565b91505092959891949750929550565b5f805f805f8060c087890312156121da576121d9611fa8565b5b5f6121e789828a01612082565b96505060206121f889828a016120dc565b955050604061220989828a01612082565b945050606061221a89828a01612082565b935050608061222b89828a016120dc565b92505060a061223c89828a0161210f565b9150509295509295509295565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261226a57612269612249565b5b8235905067ffffffffffffffff8111156122875761228661224d565b5b6020830191508360018202830111156122a3576122a2612251565b5b9250929050565b5f805f805f608086880312156122c3576122c2611fa8565b5b5f6122d0888289016120dc565b95505060206122e1888289016120dc565b94505060406122f28882890161210f565b935050606086013567ffffffffffffffff81111561231357612312611fac565b5b61231f88828901612255565b92509250509295509295909350565b61233781611fb0565b82525050565b5f6020820190506123505f83018461232e565b92915050565b5f8083601f84011261236b5761236a612249565b5b8235905067ffffffffffffffff8111156123885761238761224d565b5b6020830191508360208202830111156123a4576123a3612251565b5b9250929050565b5f805f805f805f8060a0898b0312156123c7576123c6611fa8565b5b5f6123d48b828c016120dc565b98505060206123e58b828c016120dc565b975050604089013567ffffffffffffffff81111561240657612405611fac565b5b6124128b828c01612356565b9650965050606089013567ffffffffffffffff81111561243557612434611fac565b5b6124418b828c01612356565b9450945050608089013567ffffffffffffffff81111561246457612463611fac565b5b6124708b828c01612255565b92509250509295985092959890939650565b5f805f806080858703121561249a57612499611fa8565b5b5f6124a7878288016120dc565b94505060206124b88782880161210f565b93505060406124c98782880161210f565b92505060606124da878288016120dc565b91505092959194509250565b5f602082840312156124fb576124fa611fa8565b5b5f61250884828501612082565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b61254581612511565b82525050565b5f63ffffffff82169050919050565b6125638161254b565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600481106125a7576125a6612569565b5b50565b5f8190506125b782612596565b919050565b5f6125c6826125aa565b9050919050565b6125d6816125bc565b82525050565b5f6060820190506125ef5f83018661253c565b6125fc602083018561255a565b61260960408301846125cd565b949350505050565b5f805f6060848603121561262857612627611fa8565b5b5f612635868287016120dc565b93505060206126468682870161210f565b9250506040612657868287016120dc565b9150509250925092565b5f805f805f8060a0878903121561267b5761267a611fa8565b5b5f61268889828a016120dc565b965050602061269989828a016120dc565b95505060406126aa89828a0161210f565b94505060606126bb89828a0161210f565b935050608087013567ffffffffffffffff8111156126dc576126db611fac565b5b6126e889828a01612255565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f612761602a836126f7565b915061276c82612707565b604082019050919050565b5f6020820190508181035f83015261278e81612755565b9050919050565b5f819050919050565b6127af6127aa82612063565b612795565b82525050565b5f6127c0828461279e565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6127fb826127cf565b61280581856127d9565b93506128158185602086016127e3565b80840191505092915050565b5f61282c82846127f1565b915081905092915050565b5f815190506128458161206c565b92915050565b5f602082840312156128605761285f611fa8565b5b5f61286d84828501612837565b91505092915050565b5f8160601b9050919050565b5f61288c82612876565b9050919050565b5f61289d82612882565b9050919050565b6128b56128b0826120b5565b612893565b82525050565b5f819050919050565b6128d56128d0826120f0565b6128bb565b82525050565b5f6128e6828a6128a4565b6014820191506128f682896128a4565b601482019150612906828861279e565b602082019150612916828761279e565b60208201915061292682866128a4565b60148201915061293682856128c4565b60208201915061294682846128c4565b60208201915081905098975050505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f61298f6013836126f7565b915061299a8261295b565b602082019050919050565b5f6020820190508181035f8301526129bc81612983565b9050919050565b6129cc81612063565b82525050565b5f6020820190506129e55f8301846129c3565b92915050565b6129f4816120b5565b82525050565b612a03816120f0565b82525050565b5f82825260208201905092915050565b50565b5f612a275f83612a09565b9150612a3282612a19565b5f82019050919050565b5f60a082019050612a4f5f8301876129eb565b612a5c60208301866129eb565b612a6960408301856129fa565b612a7660608301846129fa565b8181036080830152612a8781612a1c565b905095945050505050565b5f612a9d82896128a4565b601482019150612aad82886128a4565b601482019150612abd828761279e565b602082019150612acd828661279e565b602082019150612add82856128a4565b601482019150612aed82846128c4565b602082019150819050979650505050505050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f612b5b6038836126f7565b9150612b6682612b01565b604082019050919050565b5f6020820190508181035f830152612b8881612b4f565b9050919050565b5f606082019050612ba25f8301866129eb565b612baf60208301856129eb565b612bbc60408301846129fa565b949350505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612c0e82612bc8565b810181811067ffffffffffffffff82111715612c2d57612c2c612bd8565b5b80604052505050565b5f612c3f611f9f565b9050612c4b8282612c05565b919050565b612c598161254b565b8114612c63575f80fd5b50565b5f81359050612c7481612c50565b92915050565b5f60c08284031215612c8f57612c8e612bc4565b5b612c9960c0612c36565b90505f612ca884828501612082565b5f830152506020612cbb848285016120dc565b6020830152506040612ccf848285016120dc565b6040830152506060612ce384828501612082565b6060830152506080612cf784828501612082565b60808301525060a0612d0b84828501612c66565b60a08301525092915050565b5f60c08284031215612d2c57612d2b611fa8565b5b5f612d3984828501612c7a565b91505092915050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f612d9c602a836126f7565b9150612da782612d42565b604082019050919050565b5f6020820190508181035f830152612dc981612d90565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f612e04601e836126f7565b9150612e0f82612dd0565b602082019050919050565b5f6020820190508181035f830152612e3181612df8565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f612e6c601e836126f7565b9150612e7782612e38565b602082019050919050565b5f6020820190508181035f830152612e9981612e60565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f612efa6023836126f7565b9150612f0582612ea0565b604082019050919050565b5f6020820190508181035f830152612f2781612eee565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f612f62601b836126f7565b9150612f6d82612f2e565b602082019050919050565b5f6020820190508181035f830152612f8f81612f56565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f612fca601a836126f7565b9150612fd582612f96565b602082019050919050565b5f6020820190508181035f830152612ff781612fbe565b9050919050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f613032601d836126f7565b915061303d82612ffe565b602082019050919050565b5f6020820190508181035f83015261305f81613026565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f61309a6015836126f7565b91506130a582613066565b602082019050919050565b5f6020820190508181035f8301526130c78161308e565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f613128602b836126f7565b9150613133826130ce565b604082019050919050565b5f6020820190508181035f8301526131558161311c565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f613190601c836126f7565b915061319b8261315c565b602082019050919050565b5f6020820190508181035f8301526131bd81613184565b905091905056fea2646970667358221220c7235610f4c08b95d1e01bd31ff0b8b671c0f18c33212760a2ce3b09e6ad77e964736f6c63430008190033 \ No newline at end of file +6080604052348015600e575f80fd5b50612ffd8061001c5f395ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063b27e46fb1161006f578063b27e46fb1461015f578063bc197c811461017b578063c8d9009b146101ab578063c92cd12d146101c7578063efccb9eb146101e3578063f23a6e6114610215576100a7565b806301ffc9a7146100ab57806305ec158d146100db5780630f235fce146100f7578063150b7a02146101135780636e6bf6d214610143575b5f80fd5b6100c560048036038101906100c09190611ebc565b610245565b6040516100d29190611f01565b60405180910390f35b6100f560048036038101906100f09190611fda565b610326565b005b610111600480360381019061010c9190612077565b6105e6565b005b61012d60048036038101906101289190612161565b6108a0565b60405161013a91906121f4565b60405180910390f35b61015d60048036038101906101589190612077565b610cef565b005b61017960048036038101906101749190611fda565b610faa565b005b61019560048036038101906101909190612262565b611269565b6040516101a291906121f4565b60405180910390f35b6101c560048036038101906101c09190612077565b6112a5565b005b6101e160048036038101906101dc9190611fda565b6115ce565b005b6101fd60048036038101906101f89190612339565b6118fc565b60405161020c9392919061242f565b60405180910390f35b61022f600480360381019061022a9190612464565b611948565b60405161023c91906121f4565b60405180910390f35b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061030f57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061031f575061031e82611ddc565b5b9050919050565b6001600381111561033a576103396123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561036c5761036b6123bc565b5b146103ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a39061257a565b60405180910390fd5b5f600387336002896040516020016103c491906125b8565b6040516020818303038152906040526040516103e09190612624565b602060405180830381855afa1580156103fb573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061041e919061264e565b8888888860405160200161043897969594939291906126de565b6040516020818303038152906040526040516104549190612624565b602060405180830381855afa15801561046f573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146104f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f0906127a8565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561052f5761052e6123bc565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd738860405161056391906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016105ae949392919061283f565b5f604051808303815f87803b1580156105c5575f80fd5b505af11580156105d7573d5f803e3d5ffd5b50505050505050505050505050565b600160038111156105fa576105f96123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561062c5761062b6123bc565b5b1461066c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106639061257a565b60405180910390fd5b5f600386338787878760405160200161068a96959493929190612895565b6040516020818303038152906040526040516106a69190612624565b602060405180830381855afa1580156106c1573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461074b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610742906127a8565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156107b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107ad90612974565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff021916908360038111156107ec576107eb6123bc565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728760405161082091906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161086993929190612992565b5f604051808303815f87803b158015610880575f80fd5b505af1158015610892573d5f803e3d5ffd5b505050505050505050505050565b5f8083838101906108b19190612b1a565b90505f60038111156108c6576108c56123bc565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff1660038111156108fb576108fa6123bc565b5b1461093b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093290612bb5565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff16036109ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a490612c1d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610a1f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1690612c85565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8890612d13565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610aff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af690612d7b565b60405180910390fd5b610b0c8160200151611e45565b15610b4c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4390612de3565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610b7a96959493929190612895565b604051602081830303815290604052604051610b969190612624565b602060405180830381855afa158015610bb1573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610c0157610c006123bc565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610c9857610c976123bc565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610cd291906127d5565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610d0357610d026123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff166003811115610d3557610d346123bc565b5b14610d75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6c9061257a565b60405180910390fd5b5f60038633600288604051602001610d8d91906125b8565b604051602081830303815290604052604051610da99190612624565b602060405180830381855afa158015610dc4573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190610de7919061264e565b878787604051602001610dff96959493929190612895565b604051602081830303815290604052604051610e1b9190612624565b602060405180830381855afa158015610e36573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610ec0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eb7906127a8565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610ef657610ef56123bc565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051610f2a91906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401610f7393929190612992565b5f604051808303815f87803b158015610f8a575f80fd5b505af1158015610f9c573d5f803e3d5ffd5b505050505050505050505050565b60016003811115610fbe57610fbd6123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610ff057610fef6123bc565b5b14611030576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110279061257a565b60405180910390fd5b5f60038733888888888860405160200161105097969594939291906126de565b60405160208183030381529060405260405161106c9190612624565b602060405180830381855afa158015611087573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611111576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611108906127a8565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff1642101561117c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161117390612974565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156111b2576111b16123bc565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072886040516111e691906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b8152600401611231949392919061283f565b5f604051808303815f87803b158015611248575f80fd5b505af115801561125a573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161129c90612e4b565b60405180910390fd5b600160038111156112b9576112b86123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156112eb576112ea6123bc565b5b1461132b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113229061257a565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611399576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161139090612eb3565b60405180910390fd5b5f60033387876002886040516020016113b291906125b8565b6040516020818303038152906040526040516113ce9190612624565b602060405180830381855afa1580156113e9573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061140c919061264e565b878760405160200161142396959493929190612895565b60405160208183030381529060405260405161143f9190612624565b602060405180830381855afa15801561145a573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146114e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114db906127a8565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561151a576115196123bc565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161154e91906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161159793929190612992565b5f604051808303815f87803b1580156115ae575f80fd5b505af11580156115c0573d5f803e3d5ffd5b505050505050505050505050565b600160038111156115e2576115e16123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611614576116136123bc565b5b14611654576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161164b9061257a565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146116c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b990612eb3565b60405180910390fd5b5f60033388886002896040516020016116db91906125b8565b6040516020818303038152906040526040516116f79190612624565b602060405180830381855afa158015611712573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611735919061264e565b88888860405160200161174e97969594939291906126de565b60405160208183030381529060405260405161176a9190612624565b602060405180830381855afa158015611785573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461180f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611806906127a8565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff02191690836003811115611845576118446123bc565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08860405161187991906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016118c4949392919061283f565b5f604051808303815f87803b1580156118db575f80fd5b505af11580156118ed573d5f803e3d5ffd5b50505050505050505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f8083838101906119599190612b1a565b90505f600381111561196e5761196d6123bc565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff1660038111156119a3576119a26123bc565b5b146119e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119da90612f41565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603611a55576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a4c90612c1d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603611ac7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611abe90612c85565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b3090612d13565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614611ba7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9e90612d7b565b60405180910390fd5b5f8511611be9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be090612fa9565b60405180910390fd5b611bf68160200151611e45565b15611c36576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2d90612de3565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001611c6697969594939291906126de565b604051602081830303815290604052604051611c829190612624565b602060405180830381855afa158015611c9d573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115611ced57611cec6123bc565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115611d8457611d836123bc565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051611dbe91906127d5565b60405180910390a163f23a6e6160e01b925050509695505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611e9b81611e67565b8114611ea5575f80fd5b50565b5f81359050611eb681611e92565b92915050565b5f60208284031215611ed157611ed0611e5f565b5b5f611ede84828501611ea8565b91505092915050565b5f8115159050919050565b611efb81611ee7565b82525050565b5f602082019050611f145f830184611ef2565b92915050565b5f819050919050565b611f2c81611f1a565b8114611f36575f80fd5b50565b5f81359050611f4781611f23565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611f7682611f4d565b9050919050565b611f8681611f6c565b8114611f90575f80fd5b50565b5f81359050611fa181611f7d565b92915050565b5f819050919050565b611fb981611fa7565b8114611fc3575f80fd5b50565b5f81359050611fd481611fb0565b92915050565b5f805f805f805f60e0888a031215611ff557611ff4611e5f565b5b5f6120028a828b01611f39565b97505060206120138a828b01611f93565b96505060406120248a828b01611f39565b95505060606120358a828b01611f39565b94505060806120468a828b01611f93565b93505060a06120578a828b01611fc6565b92505060c06120688a828b01611fc6565b91505092959891949750929550565b5f805f805f8060c0878903121561209157612090611e5f565b5b5f61209e89828a01611f39565b96505060206120af89828a01611f93565b95505060406120c089828a01611f39565b94505060606120d189828a01611f39565b93505060806120e289828a01611f93565b92505060a06120f389828a01611fc6565b9150509295509295509295565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261212157612120612100565b5b8235905067ffffffffffffffff81111561213e5761213d612104565b5b60208301915083600182028301111561215a57612159612108565b5b9250929050565b5f805f805f6080868803121561217a57612179611e5f565b5b5f61218788828901611f93565b955050602061219888828901611f93565b94505060406121a988828901611fc6565b935050606086013567ffffffffffffffff8111156121ca576121c9611e63565b5b6121d68882890161210c565b92509250509295509295909350565b6121ee81611e67565b82525050565b5f6020820190506122075f8301846121e5565b92915050565b5f8083601f84011261222257612221612100565b5b8235905067ffffffffffffffff81111561223f5761223e612104565b5b60208301915083602082028301111561225b5761225a612108565b5b9250929050565b5f805f805f805f8060a0898b03121561227e5761227d611e5f565b5b5f61228b8b828c01611f93565b985050602061229c8b828c01611f93565b975050604089013567ffffffffffffffff8111156122bd576122bc611e63565b5b6122c98b828c0161220d565b9650965050606089013567ffffffffffffffff8111156122ec576122eb611e63565b5b6122f88b828c0161220d565b9450945050608089013567ffffffffffffffff81111561231b5761231a611e63565b5b6123278b828c0161210c565b92509250509295985092959890939650565b5f6020828403121561234e5761234d611e5f565b5b5f61235b84828501611f39565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b61239881612364565b82525050565b5f63ffffffff82169050919050565b6123b68161239e565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600481106123fa576123f96123bc565b5b50565b5f81905061240a826123e9565b919050565b5f612419826123fd565b9050919050565b6124298161240f565b82525050565b5f6060820190506124425f83018661238f565b61244f60208301856123ad565b61245c6040830184612420565b949350505050565b5f805f805f8060a0878903121561247e5761247d611e5f565b5b5f61248b89828a01611f93565b965050602061249c89828a01611f93565b95505060406124ad89828a01611fc6565b94505060606124be89828a01611fc6565b935050608087013567ffffffffffffffff8111156124df576124de611e63565b5b6124eb89828a0161210c565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f612564602a836124fa565b915061256f8261250a565b604082019050919050565b5f6020820190508181035f83015261259181612558565b9050919050565b5f819050919050565b6125b26125ad82611f1a565b612598565b82525050565b5f6125c382846125a1565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6125fe826125d2565b61260881856125dc565b93506126188185602086016125e6565b80840191505092915050565b5f61262f82846125f4565b915081905092915050565b5f8151905061264881611f23565b92915050565b5f6020828403121561266357612662611e5f565b5b5f6126708482850161263a565b91505092915050565b5f8160601b9050919050565b5f61268f82612679565b9050919050565b5f6126a082612685565b9050919050565b6126b86126b382611f6c565b612696565b82525050565b5f819050919050565b6126d86126d382611fa7565b6126be565b82525050565b5f6126e9828a6126a7565b6014820191506126f982896126a7565b60148201915061270982886125a1565b60208201915061271982876125a1565b60208201915061272982866126a7565b60148201915061273982856126c7565b60208201915061274982846126c7565b60208201915081905098975050505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f6127926013836124fa565b915061279d8261275e565b602082019050919050565b5f6020820190508181035f8301526127bf81612786565b9050919050565b6127cf81611f1a565b82525050565b5f6020820190506127e85f8301846127c6565b92915050565b6127f781611f6c565b82525050565b61280681611fa7565b82525050565b5f82825260208201905092915050565b50565b5f61282a5f8361280c565b91506128358261281c565b5f82019050919050565b5f60a0820190506128525f8301876127ee565b61285f60208301866127ee565b61286c60408301856127fd565b61287960608301846127fd565b818103608083015261288a8161281f565b905095945050505050565b5f6128a082896126a7565b6014820191506128b082886126a7565b6014820191506128c082876125a1565b6020820191506128d082866125a1565b6020820191506128e082856126a7565b6014820191506128f082846126c7565b602082019150819050979650505050505050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f61295e6038836124fa565b915061296982612904565b604082019050919050565b5f6020820190508181035f83015261298b81612952565b9050919050565b5f6060820190506129a55f8301866127ee565b6129b260208301856127ee565b6129bf60408301846127fd565b949350505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612a11826129cb565b810181811067ffffffffffffffff82111715612a3057612a2f6129db565b5b80604052505050565b5f612a42611e56565b9050612a4e8282612a08565b919050565b612a5c8161239e565b8114612a66575f80fd5b50565b5f81359050612a7781612a53565b92915050565b5f60c08284031215612a9257612a916129c7565b5b612a9c60c0612a39565b90505f612aab84828501611f39565b5f830152506020612abe84828501611f93565b6020830152506040612ad284828501611f93565b6040830152506060612ae684828501611f39565b6060830152506080612afa84828501611f39565b60808301525060a0612b0e84828501612a69565b60a08301525092915050565b5f60c08284031215612b2f57612b2e611e5f565b5b5f612b3c84828501612a7d565b91505092915050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f612b9f602a836124fa565b9150612baa82612b45565b604082019050919050565b5f6020820190508181035f830152612bcc81612b93565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f612c07601e836124fa565b9150612c1282612bd3565b602082019050919050565b5f6020820190508181035f830152612c3481612bfb565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f612c6f601e836124fa565b9150612c7a82612c3b565b602082019050919050565b5f6020820190508181035f830152612c9c81612c63565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f612cfd6023836124fa565b9150612d0882612ca3565b604082019050919050565b5f6020820190508181035f830152612d2a81612cf1565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f612d65601b836124fa565b9150612d7082612d31565b602082019050919050565b5f6020820190508181035f830152612d9281612d59565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f612dcd601a836124fa565b9150612dd882612d99565b602082019050919050565b5f6020820190508181035f830152612dfa81612dc1565b9050919050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f612e35601d836124fa565b9150612e4082612e01565b602082019050919050565b5f6020820190508181035f830152612e6281612e29565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f612e9d6015836124fa565b9150612ea882612e69565b602082019050919050565b5f6020820190508181035f830152612eca81612e91565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f612f2b602b836124fa565b9150612f3682612ed1565b604082019050919050565b5f6020820190508181035f830152612f5881612f1f565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f612f93601c836124fa565b9150612f9e82612f5f565b602082019050919050565b5f6020820190508181035f830152612fc081612f87565b905091905056fea26469706673582212208adfd9bc3010e8e9bf1d503f3e439ea5632ee575d696af59d80e0a2268d48d7e64736f6c634300081a0033 \ No newline at end of file diff --git a/mm2src/mm2_test_helpers/contract_bytes/nft_swap_contract_bytes b/mm2src/mm2_test_helpers/contract_bytes/nft_swap_contract_bytes deleted file mode 100644 index 44c1930271..0000000000 --- a/mm2src/mm2_test_helpers/contract_bytes/nft_swap_contract_bytes +++ /dev/null @@ -1 +0,0 @@ -60a060405234801562000010575f80fd5b50604051620055a2380380620055a2833981810160405281019062000036919062000147565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e90620001fb565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506200021b565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200011182620000e6565b9050919050565b620001238162000105565b81146200012e575f80fd5b50565b5f81519050620001418162000118565b92915050565b5f602082840312156200015f576200015e620000e2565b5b5f6200016e8482850162000131565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f620001e360238362000177565b9150620001f08262000187565b604082019050919050565b5f6020820190508181035f8301526200021481620001d5565b9050919050565b608051615360620002425f395f8181612aef01528181612b8a0152612f4801526153605ff3fe608060405260043610610113575f3560e01c80639b4603f21161009f578063cc90c19911610063578063cc90c1991461038e578063d6a71eb4146103b6578063e06cf966146103de578063efccb9eb14610408578063f23a6e611461044657610113565b80639b4603f2146102be578063b27e46fb146102da578063bc197c8114610302578063c8d9009b1461033e578063c92cd12d1461036657610113565b8063150b7a02116100e6578063150b7a02146101cb5780633e6af5f21461020757806346b95ac71461022f57806365e266171461026e5780636e6bf6d21461029657610113565b806301ffc9a71461011757806305ec158d146101535780630f235fce1461017b578063146e5b24146101a3575b5f80fd5b348015610122575f80fd5b5061013d6004803603810190610138919061386f565b610482565b60405161014a91906138b4565b60405180910390f35b34801561015e575f80fd5b506101796004803603810190610174919061398d565b610563565b005b348015610186575f80fd5b506101a1600480360381019061019c9190613a2a565b610823565b005b3480156101ae575f80fd5b506101c960048036038101906101c49190613ab3565b610add565b005b3480156101d6575f80fd5b506101f160048036038101906101ec9190613bb1565b610cc3565b6040516101fe9190613c44565b60405180910390f35b348015610212575f80fd5b5061022d60048036038101906102289190613ab3565b611112565b005b34801561023a575f80fd5b5061025560048036038101906102509190613c5d565b611423565b6040516102659493929190613d53565b60405180910390f35b348015610279575f80fd5b50610294600480360381019061028f9190613ab3565b611485565b005b3480156102a1575f80fd5b506102bc60048036038101906102b79190613a2a565b6118e9565b005b6102d860048036038101906102d39190613dc0565b611ba4565b005b3480156102e5575f80fd5b5061030060048036038101906102fb919061398d565b611eda565b005b34801561030d575f80fd5b5061032860048036038101906103239190613eb2565b612199565b6040516103359190613c44565b60405180910390f35b348015610349575f80fd5b50610364600480360381019061035f9190613a2a565b6121d5565b005b348015610371575f80fd5b5061038c6004803603810190610387919061398d565b6124fe565b005b348015610399575f80fd5b506103b460048036038101906103af9190613ab3565b61282c565b005b3480156103c1575f80fd5b506103dc60048036038101906103d79190613f89565b612bdc565b005b3480156103e9575f80fd5b506103f2612f46565b6040516103ff919061405c565b60405180910390f35b348015610413575f80fd5b5061042e60048036038101906104299190613c5d565b612f6a565b60405161043d939291906140bb565b60405180910390f35b348015610451575f80fd5b5061046c600480360381019061046791906140f0565b612fb6565b6040516104799190613c44565b60405180910390f35b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061054c57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061055c575061055b8261344a565b5b9050919050565b6001600381111561057757610576613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff1660038111156105a9576105a8613ce0565b5b146105e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e090614206565b60405180910390fd5b5f600387336002896040516020016106019190614244565b60405160208183030381529060405260405161061d91906142ca565b602060405180830381855afa158015610638573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061065b91906142f4565b888888886040516020016106759796959493929190614384565b60405160208183030381529060405260405161069191906142ca565b602060405180830381855afa1580156106ac573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610736576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072d9061444e565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561076c5761076b613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd73886040516107a0919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016107eb94939291906144d6565b5f604051808303815f87803b158015610802575f80fd5b505af1158015610814573d5f803e3d5ffd5b50505050505050505050505050565b6001600381111561083757610836613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561086957610868613ce0565b5b146108a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a090614206565b60405180910390fd5b5f60038633878787876040516020016108c79695949392919061452c565b6040516020818303038152906040526040516108e391906142ca565b602060405180830381855afa1580156108fe573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610988576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097f9061444e565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156109f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ea9061460b565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610a2957610a28613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad1921907287604051610a5d919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401610aa693929190614629565b5f604051808303815f87803b158015610abd575f80fd5b505af1158015610acf573d5f803e3d5ffd5b505050505050505050505050565b60016004811115610af157610af0613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115610b2457610b23613ce0565b5b14610b64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5b90614206565b60405180910390fd5b5f600387878733888888604051602001610b84979695949392919061465e565b604051602081830303815290604052604051610ba091906142ca565b602060405180830381855afa158015610bbb573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610c46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3d9061444e565b60405180910390fd5b600260015f8a81526020019081526020015f205f01601c6101000a81548160ff02191690836004811115610c7d57610c7c613ce0565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb588604051610cb1919061447b565b60405180910390a15050505050505050565b5f808383810190610cd49190614807565b90505f6003811115610ce957610ce8613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115610d1e57610d1d613ce0565b5b14610d5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d55906148a2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610dd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dc79061490a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610e42576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3990614972565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610eb4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eab90614a00565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610f22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1990614a68565b60405180910390fd5b610f2f81602001516134b3565b15610f6f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f6690614ad0565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610f9d9695949392919061452c565b604051602081830303815290604052604051610fb991906142ca565b602060405180830381855afa158015610fd4573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff1681526020016001600381111561102457611023613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156110bb576110ba613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f01516040516110f5919061447b565b60405180910390a163150b7a0260e01b9250505095945050505050565b6001600481111561112657611125613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561115957611158613ce0565b5b14611199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161119090614206565b60405180910390fd5b5f6003878787336002896040516020016111b39190614244565b6040516020818303038152906040526040516111cf91906142ca565b602060405180830381855afa1580156111ea573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061120d91906142f4565b8888604051602001611225979695949392919061465e565b60405160208183030381529060405260405161124191906142ca565b602060405180830381855afa15801561125c573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146112e7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112de9061444e565b60405180910390fd5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561131e5761131d613ce0565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f278885604051611354929190614aee565b60405180910390a15f86886113699190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036113e7573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156113e1573d5f803e3d5ffd5b50611418565b5f83905061141633838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b6001602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b6001600481111561149957611498613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156114cc576114cb613ce0565b5b148061151c5750600260048111156114e7576114e6613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561151a57611519613ce0565b5b145b61155b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155290614be5565b60405180910390fd5b5f60038787873388888860405160200161157b979695949392919061465e565b60405160208183030381529060405260405161159791906142ca565b602060405180830381855afa1580156115b2573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461163d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116349061444e565b60405180910390fd5b6002600481111561165157611650613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561168457611683613ce0565b5b036116f65760015f8981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff164210156116f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ec9061460b565b60405180910390fd5b5b6001600481111561170a57611709613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561173d5761173c613ce0565b5b036117af5760015f8981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156117ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117a590614c73565b60405180910390fd5b5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156117e6576117e5613ce0565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b9538860405161181a919061447b565b60405180910390a15f868861182f9190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036118ad573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156118a7573d5f803e3d5ffd5b506118de565b5f8390506118dc33838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b600160038111156118fd576118fc613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561192f5761192e613ce0565b5b1461196f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161196690614206565b60405180910390fd5b5f600386336002886040516020016119879190614244565b6040516020818303038152906040526040516119a391906142ca565b602060405180830381855afa1580156119be573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906119e191906142f4565b8787876040516020016119f99695949392919061452c565b604051602081830303815290604052604051611a1591906142ca565b602060405180830381855afa158015611a30573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611aba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ab19061444e565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115611af057611aef613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051611b24919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401611b6d93929190614629565b5f604051808303815f87803b158015611b84575f80fd5b505af1158015611b96573d5f803e3d5ffd5b505050505050505050505050565b5f6004811115611bb757611bb6613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115611bea57611be9613ce0565b5b14611c2a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2190614d01565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611c98576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8f90614d8f565b60405180910390fd5b5f3411611cda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd190614e1d565b60405180910390fd5b853411611d1c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d1390614eab565b60405180910390fd5b5f60038734611d2b9190614ec9565b88883389895f604051602001611d47979695949392919061465e565b604051602081830303815290604052604051611d6391906142ca565b602060405180830381855afa158015611d7e573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115611dd657611dd5613ce0565b5b81525060015f8a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115611e9157611e90613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051611ec8919061447b565b60405180910390a15050505050505050565b60016003811115611eee57611eed613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611f2057611f1f613ce0565b5b14611f60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f5790614206565b60405180910390fd5b5f600387338888888888604051602001611f809796959493929190614384565b604051602081830303815290604052604051611f9c91906142ca565b602060405180830381855afa158015611fb7573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612041576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120389061444e565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156120ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a39061460b565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156120e2576120e1613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad1921907288604051612116919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b815260040161216194939291906144d6565b5f604051808303815f87803b158015612178575f80fd5b505af115801561218a573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121cc90614f46565b60405180910390fd5b600160038111156121e9576121e8613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561221b5761221a613ce0565b5b1461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225290614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122c090614fae565b60405180910390fd5b5f60033387876002886040516020016122e29190614244565b6040516020818303038152906040526040516122fe91906142ca565b602060405180830381855afa158015612319573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061233c91906142f4565b87876040516020016123539695949392919061452c565b60405160208183030381529060405260405161236f91906142ca565b602060405180830381855afa15801561238a573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612414576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161240b9061444e565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561244a57612449613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161247e919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016124c793929190614629565b5f604051808303815f87803b1580156124de575f80fd5b505af11580156124f0573d5f803e3d5ffd5b505050505050505050505050565b6001600381111561251257612511613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561254457612543613ce0565b5b14612584576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161257b90614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146125f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125e990614fae565b60405180910390fd5b5f600333888860028960405160200161260b9190614244565b60405160208183030381529060405260405161262791906142ca565b602060405180830381855afa158015612642573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061266591906142f4565b88888860405160200161267e9796959493929190614384565b60405160208183030381529060405260405161269a91906142ca565b602060405180830381855afa1580156126b5573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461273f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016127369061444e565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561277557612774613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0886040516127a9919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016127f494939291906144d6565b5f604051808303815f87803b15801561280b575f80fd5b505af115801561281d573d5f803e3d5ffd5b50505050505050505050505050565b600260048111156128405761283f613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561287357612872613ce0565b5b146128b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128aa9061503c565b60405180910390fd5b5f600387873388886002896040516020016128ce9190614244565b6040516020818303038152906040526040516128ea91906142ca565b602060405180830381855afa158015612905573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061292891906142f4565b8860405160200161293f979695949392919061465e565b60405160208183030381529060405260405161295b91906142ca565b602060405180830381855afa158015612976573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612a01576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f89061444e565b60405180910390fd5b600360015f8a81526020019081526020015f205f01601c6101000a81548160ff02191690836004811115612a3857612a37613ce0565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a878884604051612a6e929190614aee565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612b56573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f19350505050158015612aec573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015612b50573d5f803e3d5ffd5b50612bd2565b5f829050612b8533898373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b612bd07f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b5050505050505050565b5f6004811115612bef57612bee613ce0565b5b60015f8b81526020019081526020015f205f01601c9054906101000a900460ff166004811115612c2257612c21613ce0565b5b14612c62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c59906150ca565b60405180910390fd5b5f8811612ca4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9b90615132565b60405180910390fd5b5f8711612ce6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cdd9061519a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612d54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d4b90614d8f565b60405180910390fd5b5f60038989883389898d604051602001612d74979695949392919061465e565b604051602081830303815290604052604051612d9091906142ca565b602060405180830381855afa158015612dab573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115612e0357612e02613ce0565b5b81525060015f8c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115612ebe57612ebd613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a604051612ef5919061447b565b60405180910390a15f879050612f3933308b8d612f129190614b42565b8473ffffffffffffffffffffffffffffffffffffffff16613543909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f808383810190612fc79190614807565b90505f6003811115612fdc57612fdb613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff16600381111561301157613010613ce0565b5b14613051576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161304890615228565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff16036130c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130ba9061490a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603613135576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161312c90614972565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146131a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161319e90614a00565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614613215576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320c90614a68565b60405180910390fd5b5f8511613257576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161324e90615290565b60405180910390fd5b61326481602001516134b3565b156132a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161329b90614ad0565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c6040516020016132d49796959493929190614384565b6040516020818303038152906040526040516132f091906142ca565b602060405180830381855afa15801561330b573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff1681526020016001600381111561335b5761335a613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156133f2576133f1613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f015160405161342c919061447b565b60405180910390a163f23a6e6160e01b925050509695505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b61353e838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016134f79291906152ae565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b505050565b6135bf848573ffffffffffffffffffffffffffffffffffffffff166323b872dd86868660405160240161357893929190614629565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b50505050565b5f6135ef828473ffffffffffffffffffffffffffffffffffffffff1661365a90919063ffffffff16565b90505f81511415801561361357508080602001905181019061361191906152ff565b155b1561365557826040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161364c919061405c565b60405180910390fd5b505050565b606061366783835f61366f565b905092915050565b6060814710156136b657306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016136ad919061405c565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516136de91906142ca565b5f6040518083038185875af1925050503d805f8114613718576040519150601f19603f3d011682016040523d82523d5f602084013e61371d565b606091505b509150915061372d868383613738565b925050509392505050565b60608261374d57613748826137c5565b6137bd565b5f825114801561377357505f8473ffffffffffffffffffffffffffffffffffffffff163b145b156137b557836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016137ac919061405c565b60405180910390fd5b8190506137be565b5b9392505050565b5f815111156137d75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61384e8161381a565b8114613858575f80fd5b50565b5f8135905061386981613845565b92915050565b5f6020828403121561388457613883613812565b5b5f6138918482850161385b565b91505092915050565b5f8115159050919050565b6138ae8161389a565b82525050565b5f6020820190506138c75f8301846138a5565b92915050565b5f819050919050565b6138df816138cd565b81146138e9575f80fd5b50565b5f813590506138fa816138d6565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61392982613900565b9050919050565b6139398161391f565b8114613943575f80fd5b50565b5f8135905061395481613930565b92915050565b5f819050919050565b61396c8161395a565b8114613976575f80fd5b50565b5f8135905061398781613963565b92915050565b5f805f805f805f60e0888a0312156139a8576139a7613812565b5b5f6139b58a828b016138ec565b97505060206139c68a828b01613946565b96505060406139d78a828b016138ec565b95505060606139e88a828b016138ec565b94505060806139f98a828b01613946565b93505060a0613a0a8a828b01613979565b92505060c0613a1b8a828b01613979565b91505092959891949750929550565b5f805f805f8060c08789031215613a4457613a43613812565b5b5f613a5189828a016138ec565b9650506020613a6289828a01613946565b9550506040613a7389828a016138ec565b9450506060613a8489828a016138ec565b9350506080613a9589828a01613946565b92505060a0613aa689828a01613979565b9150509295509295509295565b5f805f805f805f60e0888a031215613ace57613acd613812565b5b5f613adb8a828b016138ec565b9750506020613aec8a828b01613979565b9650506040613afd8a828b01613979565b9550506060613b0e8a828b01613946565b9450506080613b1f8a828b016138ec565b93505060a0613b308a828b016138ec565b92505060c0613b418a828b01613946565b91505092959891949750929550565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112613b7157613b70613b50565b5b8235905067ffffffffffffffff811115613b8e57613b8d613b54565b5b602083019150836001820283011115613baa57613ba9613b58565b5b9250929050565b5f805f805f60808688031215613bca57613bc9613812565b5b5f613bd788828901613946565b9550506020613be888828901613946565b9450506040613bf988828901613979565b935050606086013567ffffffffffffffff811115613c1a57613c19613816565b5b613c2688828901613b5c565b92509250509295509295909350565b613c3e8161381a565b82525050565b5f602082019050613c575f830184613c35565b92915050565b5f60208284031215613c7257613c71613812565b5b5f613c7f848285016138ec565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b613cbc81613c88565b82525050565b5f63ffffffff82169050919050565b613cda81613cc2565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110613d1e57613d1d613ce0565b5b50565b5f819050613d2e82613d0d565b919050565b5f613d3d82613d21565b9050919050565b613d4d81613d33565b82525050565b5f608082019050613d665f830187613cb3565b613d736020830186613cd1565b613d806040830185613cd1565b613d8d6060830184613d44565b95945050505050565b613d9f81613cc2565b8114613da9575f80fd5b50565b5f81359050613dba81613d96565b92915050565b5f805f805f805f60e0888a031215613ddb57613dda613812565b5b5f613de88a828b016138ec565b9750506020613df98a828b01613979565b9650506040613e0a8a828b01613946565b9550506060613e1b8a828b016138ec565b9450506080613e2c8a828b016138ec565b93505060a0613e3d8a828b01613dac565b92505060c0613e4e8a828b01613dac565b91505092959891949750929550565b5f8083601f840112613e7257613e71613b50565b5b8235905067ffffffffffffffff811115613e8f57613e8e613b54565b5b602083019150836020820283011115613eab57613eaa613b58565b5b9250929050565b5f805f805f805f8060a0898b031215613ece57613ecd613812565b5b5f613edb8b828c01613946565b9850506020613eec8b828c01613946565b975050604089013567ffffffffffffffff811115613f0d57613f0c613816565b5b613f198b828c01613e5d565b9650965050606089013567ffffffffffffffff811115613f3c57613f3b613816565b5b613f488b828c01613e5d565b9450945050608089013567ffffffffffffffff811115613f6b57613f6a613816565b5b613f778b828c01613b5c565b92509250509295985092959890939650565b5f805f805f805f805f6101208a8c031215613fa757613fa6613812565b5b5f613fb48c828d016138ec565b9950506020613fc58c828d01613979565b9850506040613fd68c828d01613979565b9750506060613fe78c828d01613946565b9650506080613ff88c828d01613946565b95505060a06140098c828d016138ec565b94505060c061401a8c828d016138ec565b93505060e061402b8c828d01613dac565b92505061010061403d8c828d01613dac565b9150509295985092959850929598565b6140568161391f565b82525050565b5f60208201905061406f5f83018461404d565b92915050565b6004811061408657614085613ce0565b5b50565b5f81905061409682614075565b919050565b5f6140a582614089565b9050919050565b6140b58161409b565b82525050565b5f6060820190506140ce5f830186613cb3565b6140db6020830185613cd1565b6140e860408301846140ac565b949350505050565b5f805f805f8060a0878903121561410a57614109613812565b5b5f61411789828a01613946565b965050602061412889828a01613946565b955050604061413989828a01613979565b945050606061414a89828a01613979565b935050608087013567ffffffffffffffff81111561416b5761416a613816565b5b61417789828a01613b5c565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f6141f0602a83614186565b91506141fb82614196565b604082019050919050565b5f6020820190508181035f83015261421d816141e4565b9050919050565b5f819050919050565b61423e614239826138cd565b614224565b82525050565b5f61424f828461422d565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b5f5b8381101561428f578082015181840152602081019050614274565b5f8484015250505050565b5f6142a48261425e565b6142ae8185614268565b93506142be818560208601614272565b80840191505092915050565b5f6142d5828461429a565b915081905092915050565b5f815190506142ee816138d6565b92915050565b5f6020828403121561430957614308613812565b5b5f614316848285016142e0565b91505092915050565b5f8160601b9050919050565b5f6143358261431f565b9050919050565b5f6143468261432b565b9050919050565b61435e6143598261391f565b61433c565b82525050565b5f819050919050565b61437e6143798261395a565b614364565b82525050565b5f61438f828a61434d565b60148201915061439f828961434d565b6014820191506143af828861422d565b6020820191506143bf828761422d565b6020820191506143cf828661434d565b6014820191506143df828561436d565b6020820191506143ef828461436d565b60208201915081905098975050505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f614438601383614186565b915061444382614404565b602082019050919050565b5f6020820190508181035f8301526144658161442c565b9050919050565b614475816138cd565b82525050565b5f60208201905061448e5f83018461446c565b92915050565b61449d8161395a565b82525050565b5f82825260208201905092915050565b50565b5f6144c15f836144a3565b91506144cc826144b3565b5f82019050919050565b5f60a0820190506144e95f83018761404d565b6144f6602083018661404d565b6145036040830185614494565b6145106060830184614494565b8181036080830152614521816144b6565b905095945050505050565b5f614537828961434d565b601482019150614547828861434d565b601482019150614557828761422d565b602082019150614567828661422d565b602082019150614577828561434d565b601482019150614587828461436d565b602082019150819050979650505050505050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f6145f5603883614186565b91506146008261459b565b604082019050919050565b5f6020820190508181035f830152614622816145e9565b9050919050565b5f60608201905061463c5f83018661404d565b614649602083018561404d565b6146566040830184614494565b949350505050565b5f614669828a61436d565b602082019150614679828961436d565b602082019150614689828861434d565b601482019150614699828761434d565b6014820191506146a9828661422d565b6020820191506146b9828561422d565b6020820191506146c9828461434d565b60148201915081905098975050505050505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b614728826146e2565b810181811067ffffffffffffffff82111715614747576147466146f2565b5b80604052505050565b5f614759613809565b9050614765828261471f565b919050565b5f60c0828403121561477f5761477e6146de565b5b61478960c0614750565b90505f614798848285016138ec565b5f8301525060206147ab84828501613946565b60208301525060406147bf84828501613946565b60408301525060606147d3848285016138ec565b60608301525060806147e7848285016138ec565b60808301525060a06147fb84828501613dac565b60a08301525092915050565b5f60c0828403121561481c5761481b613812565b5b5f6148298482850161476a565b91505092915050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f61488c602a83614186565b915061489782614832565b604082019050919050565b5f6020820190508181035f8301526148b981614880565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f6148f4601e83614186565b91506148ff826148c0565b602082019050919050565b5f6020820190508181035f830152614921816148e8565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f61495c601e83614186565b915061496782614928565b602082019050919050565b5f6020820190508181035f83015261498981614950565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f6149ea602383614186565b91506149f582614990565b604082019050919050565b5f6020820190508181035f830152614a17816149de565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f614a52601b83614186565b9150614a5d82614a1e565b602082019050919050565b5f6020820190508181035f830152614a7f81614a46565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f614aba601a83614186565b9150614ac582614a86565b602082019050919050565b5f6020820190508181035f830152614ae781614aae565b9050919050565b5f604082019050614b015f83018561446c565b614b0e602083018461446c565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614b4c8261395a565b9150614b578361395a565b9250828201905080821115614b6f57614b6e614b15565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f614bcf603b83614186565b9150614bda82614b75565b604082019050919050565b5f6020820190508181035f830152614bfc81614bc3565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f614c5d603d83614186565b9150614c6882614c03565b604082019050919050565b5f6020820190508181035f830152614c8a81614c51565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f614ceb602483614186565b9150614cf682614c91565b604082019050919050565b5f6020820190508181035f830152614d1881614cdf565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f614d79602183614186565b9150614d8482614d1f565b604082019050919050565b5f6020820190508181035f830152614da681614d6d565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f614e07602383614186565b9150614e1282614dad565b604082019050919050565b5f6020820190508181035f830152614e3481614dfb565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f614e95602683614186565b9150614ea082614e3b565b604082019050919050565b5f6020820190508181035f830152614ec281614e89565b9050919050565b5f614ed38261395a565b9150614ede8361395a565b9250828203905081811115614ef657614ef5614b15565b5b92915050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f614f30601d83614186565b9150614f3b82614efc565b602082019050919050565b5f6020820190508181035f830152614f5d81614f24565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f614f98601583614186565b9150614fa382614f64565b602082019050919050565b5f6020820190508181035f830152614fc581614f8c565b9050919050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f615026602c83614186565b915061503182614fcc565b604082019050919050565b5f6020820190508181035f8301526150538161501a565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f6150b4602783614186565b91506150bf8261505a565b604082019050919050565b5f6020820190508181035f8301526150e1816150a8565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f61511c601783614186565b9150615127826150e8565b602082019050919050565b5f6020820190508181035f83015261514981615110565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f615184601883614186565b915061518f82615150565b602082019050919050565b5f6020820190508181035f8301526151b181615178565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f615212602b83614186565b915061521d826151b8565b604082019050919050565b5f6020820190508181035f83015261523f81615206565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f61527a601c83614186565b915061528582615246565b602082019050919050565b5f6020820190508181035f8301526152a78161526e565b9050919050565b5f6040820190506152c15f83018561404d565b6152ce6020830184614494565b9392505050565b6152de8161389a565b81146152e8575f80fd5b50565b5f815190506152f9816152d5565b92915050565b5f6020828403121561531457615313613812565b5b5f615321848285016152eb565b9150509291505056fea26469706673582212200d86b0f6898fb823c55626c3b02a7098bc8622606b092e0f458df6c86ce2967864736f6c63430008180033 \ No newline at end of file diff --git a/mm2src/mm2_test_helpers/contract_bytes/taker_swap_v2_bytes b/mm2src/mm2_test_helpers/contract_bytes/taker_swap_v2_bytes index 5394d75e8a..ea4cd8c817 100644 --- a/mm2src/mm2_test_helpers/contract_bytes/taker_swap_v2_bytes +++ b/mm2src/mm2_test_helpers/contract_bytes/taker_swap_v2_bytes @@ -1 +1 @@ -60a060405234801561000f575f80fd5b50604051612a1b380380612a1b83398181016040528101906100319190610137565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361009f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610096906101e2565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff168152505050610200565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610106826100dd565b9050919050565b610116816100fc565b8114610120575f80fd5b50565b5f815190506101318161010d565b92915050565b5f6020828403121561014c5761014b6100d9565b5b5f61015984828501610123565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f6101cc602383610162565b91506101d782610172565b604082019050919050565b5f6020820190508181035f8301526101f9816101c0565b9050919050565b6080516127f56102265f395f818161116d0152818161120801526115c401526127f55ff3fe60806040526004361061007a575f3560e01c80639b4603f21161004d5780639b4603f214610135578063cc90c19914610151578063d6a71eb414610179578063e06cf966146101a15761007a565b8063146e5b241461007e5780633e6af5f2146100a657806346b95ac7146100ce57806365e266171461010d575b5f80fd5b348015610089575f80fd5b506100a4600480360381019061009f91906119ef565b6101cb565b005b3480156100b1575f80fd5b506100cc60048036038101906100c791906119ef565b6103ae565b005b3480156100d9575f80fd5b506100f460048036038101906100ef9190611a8c565b6106bc565b6040516101049493929190611b82565b60405180910390f35b348015610118575f80fd5b50610133600480360381019061012e91906119ef565b61071d565b005b61014f600480360381019061014a9190611bef565b610b79565b005b34801561015c575f80fd5b50610177600480360381019061017291906119ef565b610ead565b005b348015610184575f80fd5b5061019f600480360381019061019a9190611c8c565b61125a565b005b3480156101ac575f80fd5b506101b56115c2565b6040516101c29190611d5f565b60405180910390f35b600160048111156101df576101de611b0f565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff16600481111561021157610210611b0f565b5b14610251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161024890611df8565b60405180910390fd5b5f6003878787338888886040516020016102719796959493929190611e9b565b60405160208183030381529060405260405161028d9190611f6d565b602060405180830381855afa1580156102a8573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610332576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032990611fcd565b60405180910390fd5b60025f808a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561036857610367611b0f565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb58860405161039c9190611ffa565b60405180910390a15050505050505050565b600160048111156103c2576103c1611b0f565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff1660048111156103f4576103f3611b0f565b5b14610434576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161042b90611df8565b60405180910390fd5b5f60038787873360028960405160200161044e9190612013565b60405160208183030381529060405260405161046a9190611f6d565b602060405180830381855afa158015610485573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906104a89190612041565b88886040516020016104c09796959493929190611e9b565b6040516020818303038152906040526040516104dc9190611f6d565b602060405180830381855afa1580156104f7573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610581576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057890611fcd565b60405180910390fd5b60045f808a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156105b7576105b6611b0f565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f2788856040516105ed92919061206c565b60405180910390a15f868861060291906120c0565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610680573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f1935050505015801561067a573d5f803e3d5ffd5b506106b1565b5f8390506106af33838373ffffffffffffffffffffffffffffffffffffffff166115e69092919063ffffffff16565b505b505050505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b6001600481111561073157610730611b0f565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff16600481111561076357610762611b0f565b5b14806107b257506002600481111561077e5761077d611b0f565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff1660048111156107b0576107af611b0f565b5b145b6107f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e890612163565b60405180910390fd5b5f6003878787338888886040516020016108119796959493929190611e9b565b60405160208183030381529060405260405161082d9190611f6d565b602060405180830381855afa158015610848573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146108d2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108c990611fcd565b60405180910390fd5b600260048111156108e6576108e5611b0f565b5b5f808a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561091857610917611b0f565b5b03610989575f808981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff16421015610988576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097f906121f1565b60405180910390fd5b5b6001600481111561099d5761099c611b0f565b5b5f808a81526020019081526020015f205f01601c9054906101000a900460ff1660048111156109cf576109ce611b0f565b5b03610a40575f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610a3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a369061227f565b60405180910390fd5b5b60045f808a81526020019081526020015f205f01601c6101000a81548160ff02191690836004811115610a7657610a75611b0f565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b95388604051610aaa9190611ffa565b60405180910390a15f8688610abf91906120c0565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610b3d573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015610b37573d5f803e3d5ffd5b50610b6e565b5f839050610b6c33838373ffffffffffffffffffffffffffffffffffffffff166115e69092919063ffffffff16565b505b505050505050505050565b5f6004811115610b8c57610b8b611b0f565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff166004811115610bbe57610bbd611b0f565b5b14610bfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf59061230d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610c6c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c639061239b565b60405180910390fd5b5f3411610cae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca590612429565b60405180910390fd5b853411610cf0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ce7906124b7565b60405180910390fd5b5f60038734610cff91906124d5565b88883389895f604051602001610d1b9796959493929190611e9b565b604051602081830303815290604052604051610d379190611f6d565b602060405180830381855afa158015610d52573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115610daa57610da9611b0f565b5b8152505f808a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115610e6457610e63611b0f565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051610e9b9190611ffa565b60405180910390a15050505050505050565b60026004811115610ec157610ec0611b0f565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff166004811115610ef357610ef2611b0f565b5b14610f33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f2a90612578565b60405180910390fd5b5f60038787338888600289604051602001610f4e9190612013565b604051602081830303815290604052604051610f6a9190611f6d565b602060405180830381855afa158015610f85573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190610fa89190612041565b88604051602001610fbf9796959493929190611e9b565b604051602081830303815290604052604051610fdb9190611f6d565b602060405180830381855afa158015610ff6573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611080576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161107790611fcd565b60405180910390fd5b60035f808a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156110b6576110b5611b0f565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a8788846040516110ec92919061206c565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036111d4573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f1935050505015801561116a573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f193505050501580156111ce573d5f803e3d5ffd5b50611250565b5f82905061120333898373ffffffffffffffffffffffffffffffffffffffff166115e69092919063ffffffff16565b61124e7f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff166115e69092919063ffffffff16565b505b5050505050505050565b5f600481111561126d5761126c611b0f565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff16600481111561129f5761129e611b0f565b5b146112df576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d690612606565b60405180910390fd5b5f8811611321576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113189061266e565b60405180910390fd5b5f8711611363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161135a906126d6565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036113d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113c89061239b565b60405180910390fd5b5f60038989883389898d6040516020016113f19796959493929190611e9b565b60405160208183030381529060405260405161140d9190611f6d565b602060405180830381855afa158015611428573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff168152602001600160048111156114805761147f611b0f565b5b8152505f808c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff0219169083600481111561153a57611539611b0f565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a6040516115719190611ffa565b60405180910390a15f8790506115b533308b8d61158e91906120c0565b8473ffffffffffffffffffffffffffffffffffffffff16611665909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b611660838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8585604051602401611619929190612703565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506116e7565b505050565b6116e1848573ffffffffffffffffffffffffffffffffffffffff166323b872dd86868660405160240161169a9392919061272a565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506116e7565b50505050565b5f611711828473ffffffffffffffffffffffffffffffffffffffff1661177c90919063ffffffff16565b90505f8151141580156117355750808060200190518101906117339190612794565b155b1561177757826040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161176e9190611d5f565b60405180910390fd5b505050565b606061178983835f611791565b905092915050565b6060814710156117d857306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016117cf9190611d5f565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516118009190611f6d565b5f6040518083038185875af1925050503d805f811461183a576040519150601f19603f3d011682016040523d82523d5f602084013e61183f565b606091505b509150915061184f86838361185a565b925050509392505050565b60608261186f5761186a826118e7565b6118df565b5f825114801561189557505f8473ffffffffffffffffffffffffffffffffffffffff163b145b156118d757836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016118ce9190611d5f565b60405180910390fd5b8190506118e0565b5b9392505050565b5f815111156118f95780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80fd5b5f819050919050565b6119418161192f565b811461194b575f80fd5b50565b5f8135905061195c81611938565b92915050565b5f819050919050565b61197481611962565b811461197e575f80fd5b50565b5f8135905061198f8161196b565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6119be82611995565b9050919050565b6119ce816119b4565b81146119d8575f80fd5b50565b5f813590506119e9816119c5565b92915050565b5f805f805f805f60e0888a031215611a0a57611a0961192b565b5b5f611a178a828b0161194e565b9750506020611a288a828b01611981565b9650506040611a398a828b01611981565b9550506060611a4a8a828b016119db565b9450506080611a5b8a828b0161194e565b93505060a0611a6c8a828b0161194e565b92505060c0611a7d8a828b016119db565b91505092959891949750929550565b5f60208284031215611aa157611aa061192b565b5b5f611aae8482850161194e565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b611aeb81611ab7565b82525050565b5f63ffffffff82169050919050565b611b0981611af1565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110611b4d57611b4c611b0f565b5b50565b5f819050611b5d82611b3c565b919050565b5f611b6c82611b50565b9050919050565b611b7c81611b62565b82525050565b5f608082019050611b955f830187611ae2565b611ba26020830186611b00565b611baf6040830185611b00565b611bbc6060830184611b73565b95945050505050565b611bce81611af1565b8114611bd8575f80fd5b50565b5f81359050611be981611bc5565b92915050565b5f805f805f805f60e0888a031215611c0a57611c0961192b565b5b5f611c178a828b0161194e565b9750506020611c288a828b01611981565b9650506040611c398a828b016119db565b9550506060611c4a8a828b0161194e565b9450506080611c5b8a828b0161194e565b93505060a0611c6c8a828b01611bdb565b92505060c0611c7d8a828b01611bdb565b91505092959891949750929550565b5f805f805f805f805f6101208a8c031215611caa57611ca961192b565b5b5f611cb78c828d0161194e565b9950506020611cc88c828d01611981565b9850506040611cd98c828d01611981565b9750506060611cea8c828d016119db565b9650506080611cfb8c828d016119db565b95505060a0611d0c8c828d0161194e565b94505060c0611d1d8c828d0161194e565b93505060e0611d2e8c828d01611bdb565b925050610100611d408c828d01611bdb565b9150509295985092959850929598565b611d59816119b4565b82525050565b5f602082019050611d725f830184611d50565b92915050565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f611de2602a83611d78565b9150611ded82611d88565b604082019050919050565b5f6020820190508181035f830152611e0f81611dd6565b9050919050565b5f819050919050565b611e30611e2b82611962565b611e16565b82525050565b5f8160601b9050919050565b5f611e4c82611e36565b9050919050565b5f611e5d82611e42565b9050919050565b611e75611e70826119b4565b611e53565b82525050565b5f819050919050565b611e95611e908261192f565b611e7b565b82525050565b5f611ea6828a611e1f565b602082019150611eb68289611e1f565b602082019150611ec68288611e64565b601482019150611ed68287611e64565b601482019150611ee68286611e84565b602082019150611ef68285611e84565b602082019150611f068284611e64565b60148201915081905098975050505050505050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f611f4782611f1b565b611f518185611f25565b9350611f61818560208601611f2f565b80840191505092915050565b5f611f788284611f3d565b915081905092915050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f611fb7601383611d78565b9150611fc282611f83565b602082019050919050565b5f6020820190508181035f830152611fe481611fab565b9050919050565b611ff48161192f565b82525050565b5f60208201905061200d5f830184611feb565b92915050565b5f61201e8284611e84565b60208201915081905092915050565b5f8151905061203b81611938565b92915050565b5f602082840312156120565761205561192b565b5b5f6120638482850161202d565b91505092915050565b5f60408201905061207f5f830185611feb565b61208c6020830184611feb565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6120ca82611962565b91506120d583611962565b92508282019050808211156120ed576120ec612093565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f61214d603b83611d78565b9150612158826120f3565b604082019050919050565b5f6020820190508181035f83015261217a81612141565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f6121db603883611d78565b91506121e682612181565b604082019050919050565b5f6020820190508181035f830152612208816121cf565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f612269603d83611d78565b91506122748261220f565b604082019050919050565b5f6020820190508181035f8301526122968161225d565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f6122f7602483611d78565b91506123028261229d565b604082019050919050565b5f6020820190508181035f830152612324816122eb565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f612385602183611d78565b91506123908261232b565b604082019050919050565b5f6020820190508181035f8301526123b281612379565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f612413602383611d78565b915061241e826123b9565b604082019050919050565b5f6020820190508181035f83015261244081612407565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f6124a1602683611d78565b91506124ac82612447565b604082019050919050565b5f6020820190508181035f8301526124ce81612495565b9050919050565b5f6124df82611962565b91506124ea83611962565b925082820390508181111561250257612501612093565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f612562602c83611d78565b915061256d82612508565b604082019050919050565b5f6020820190508181035f83015261258f81612556565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f6125f0602783611d78565b91506125fb82612596565b604082019050919050565b5f6020820190508181035f83015261261d816125e4565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f612658601783611d78565b915061266382612624565b602082019050919050565b5f6020820190508181035f8301526126858161264c565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f6126c0601883611d78565b91506126cb8261268c565b602082019050919050565b5f6020820190508181035f8301526126ed816126b4565b9050919050565b6126fd81611962565b82525050565b5f6040820190506127165f830185611d50565b61272360208301846126f4565b9392505050565b5f60608201905061273d5f830186611d50565b61274a6020830185611d50565b61275760408301846126f4565b949350505050565b5f8115159050919050565b6127738161275f565b811461277d575f80fd5b50565b5f8151905061278e8161276a565b92915050565b5f602082840312156127a9576127a861192b565b5b5f6127b684828501612780565b9150509291505056fea2646970667358221220fd2a736cddd6ebbd2831b0e65fb5470ffebd789dc32c1d3782ce69362e16fae564736f6c63430008190033 \ No newline at end of file +6080604052348015600e575f80fd5b50612ffd8061001c5f395ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063b27e46fb1161006f578063b27e46fb1461015f578063bc197c811461017b578063c8d9009b146101ab578063c92cd12d146101c7578063efccb9eb146101e3578063f23a6e6114610215576100a7565b806301ffc9a7146100ab57806305ec158d146100db5780630f235fce146100f7578063150b7a02146101135780636e6bf6d214610143575b5f80fd5b6100c560048036038101906100c09190611ebc565b610245565b6040516100d29190611f01565b60405180910390f35b6100f560048036038101906100f09190611fda565b610326565b005b610111600480360381019061010c9190612077565b6105e6565b005b61012d60048036038101906101289190612161565b6108a0565b60405161013a91906121f4565b60405180910390f35b61015d60048036038101906101589190612077565b610cef565b005b61017960048036038101906101749190611fda565b610faa565b005b61019560048036038101906101909190612262565b611269565b6040516101a291906121f4565b60405180910390f35b6101c560048036038101906101c09190612077565b6112a5565b005b6101e160048036038101906101dc9190611fda565b6115ce565b005b6101fd60048036038101906101f89190612339565b6118fc565b60405161020c9392919061242f565b60405180910390f35b61022f600480360381019061022a9190612464565b611948565b60405161023c91906121f4565b60405180910390f35b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061030f57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061031f575061031e82611ddc565b5b9050919050565b6001600381111561033a576103396123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561036c5761036b6123bc565b5b146103ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a39061257a565b60405180910390fd5b5f600387336002896040516020016103c491906125b8565b6040516020818303038152906040526040516103e09190612624565b602060405180830381855afa1580156103fb573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061041e919061264e565b8888888860405160200161043897969594939291906126de565b6040516020818303038152906040526040516104549190612624565b602060405180830381855afa15801561046f573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146104f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f0906127a8565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561052f5761052e6123bc565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd738860405161056391906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016105ae949392919061283f565b5f604051808303815f87803b1580156105c5575f80fd5b505af11580156105d7573d5f803e3d5ffd5b50505050505050505050505050565b600160038111156105fa576105f96123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561062c5761062b6123bc565b5b1461066c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106639061257a565b60405180910390fd5b5f600386338787878760405160200161068a96959493929190612895565b6040516020818303038152906040526040516106a69190612624565b602060405180830381855afa1580156106c1573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461074b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610742906127a8565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156107b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107ad90612974565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff021916908360038111156107ec576107eb6123bc565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728760405161082091906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161086993929190612992565b5f604051808303815f87803b158015610880575f80fd5b505af1158015610892573d5f803e3d5ffd5b505050505050505050505050565b5f8083838101906108b19190612b1a565b90505f60038111156108c6576108c56123bc565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff1660038111156108fb576108fa6123bc565b5b1461093b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093290612bb5565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff16036109ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a490612c1d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610a1f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1690612c85565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8890612d13565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610aff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af690612d7b565b60405180910390fd5b610b0c8160200151611e45565b15610b4c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4390612de3565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610b7a96959493929190612895565b604051602081830303815290604052604051610b969190612624565b602060405180830381855afa158015610bb1573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610c0157610c006123bc565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610c9857610c976123bc565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610cd291906127d5565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610d0357610d026123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff166003811115610d3557610d346123bc565b5b14610d75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6c9061257a565b60405180910390fd5b5f60038633600288604051602001610d8d91906125b8565b604051602081830303815290604052604051610da99190612624565b602060405180830381855afa158015610dc4573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190610de7919061264e565b878787604051602001610dff96959493929190612895565b604051602081830303815290604052604051610e1b9190612624565b602060405180830381855afa158015610e36573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610ec0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eb7906127a8565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610ef657610ef56123bc565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051610f2a91906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401610f7393929190612992565b5f604051808303815f87803b158015610f8a575f80fd5b505af1158015610f9c573d5f803e3d5ffd5b505050505050505050505050565b60016003811115610fbe57610fbd6123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610ff057610fef6123bc565b5b14611030576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110279061257a565b60405180910390fd5b5f60038733888888888860405160200161105097969594939291906126de565b60405160208183030381529060405260405161106c9190612624565b602060405180830381855afa158015611087573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611111576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611108906127a8565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff1642101561117c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161117390612974565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156111b2576111b16123bc565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072886040516111e691906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b8152600401611231949392919061283f565b5f604051808303815f87803b158015611248575f80fd5b505af115801561125a573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161129c90612e4b565b60405180910390fd5b600160038111156112b9576112b86123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156112eb576112ea6123bc565b5b1461132b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113229061257a565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611399576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161139090612eb3565b60405180910390fd5b5f60033387876002886040516020016113b291906125b8565b6040516020818303038152906040526040516113ce9190612624565b602060405180830381855afa1580156113e9573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061140c919061264e565b878760405160200161142396959493929190612895565b60405160208183030381529060405260405161143f9190612624565b602060405180830381855afa15801561145a573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146114e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114db906127a8565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561151a576115196123bc565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161154e91906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161159793929190612992565b5f604051808303815f87803b1580156115ae575f80fd5b505af11580156115c0573d5f803e3d5ffd5b505050505050505050505050565b600160038111156115e2576115e16123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611614576116136123bc565b5b14611654576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161164b9061257a565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146116c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b990612eb3565b60405180910390fd5b5f60033388886002896040516020016116db91906125b8565b6040516020818303038152906040526040516116f79190612624565b602060405180830381855afa158015611712573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611735919061264e565b88888860405160200161174e97969594939291906126de565b60405160208183030381529060405260405161176a9190612624565b602060405180830381855afa158015611785573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461180f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611806906127a8565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff02191690836003811115611845576118446123bc565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08860405161187991906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016118c4949392919061283f565b5f604051808303815f87803b1580156118db575f80fd5b505af11580156118ed573d5f803e3d5ffd5b50505050505050505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f8083838101906119599190612b1a565b90505f600381111561196e5761196d6123bc565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff1660038111156119a3576119a26123bc565b5b146119e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119da90612f41565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603611a55576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a4c90612c1d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603611ac7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611abe90612c85565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b3090612d13565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614611ba7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9e90612d7b565b60405180910390fd5b5f8511611be9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be090612fa9565b60405180910390fd5b611bf68160200151611e45565b15611c36576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2d90612de3565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001611c6697969594939291906126de565b604051602081830303815290604052604051611c829190612624565b602060405180830381855afa158015611c9d573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115611ced57611cec6123bc565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115611d8457611d836123bc565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051611dbe91906127d5565b60405180910390a163f23a6e6160e01b925050509695505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611e9b81611e67565b8114611ea5575f80fd5b50565b5f81359050611eb681611e92565b92915050565b5f60208284031215611ed157611ed0611e5f565b5b5f611ede84828501611ea8565b91505092915050565b5f8115159050919050565b611efb81611ee7565b82525050565b5f602082019050611f145f830184611ef2565b92915050565b5f819050919050565b611f2c81611f1a565b8114611f36575f80fd5b50565b5f81359050611f4781611f23565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611f7682611f4d565b9050919050565b611f8681611f6c565b8114611f90575f80fd5b50565b5f81359050611fa181611f7d565b92915050565b5f819050919050565b611fb981611fa7565b8114611fc3575f80fd5b50565b5f81359050611fd481611fb0565b92915050565b5f805f805f805f60e0888a031215611ff557611ff4611e5f565b5b5f6120028a828b01611f39565b97505060206120138a828b01611f93565b96505060406120248a828b01611f39565b95505060606120358a828b01611f39565b94505060806120468a828b01611f93565b93505060a06120578a828b01611fc6565b92505060c06120688a828b01611fc6565b91505092959891949750929550565b5f805f805f8060c0878903121561209157612090611e5f565b5b5f61209e89828a01611f39565b96505060206120af89828a01611f93565b95505060406120c089828a01611f39565b94505060606120d189828a01611f39565b93505060806120e289828a01611f93565b92505060a06120f389828a01611fc6565b9150509295509295509295565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261212157612120612100565b5b8235905067ffffffffffffffff81111561213e5761213d612104565b5b60208301915083600182028301111561215a57612159612108565b5b9250929050565b5f805f805f6080868803121561217a57612179611e5f565b5b5f61218788828901611f93565b955050602061219888828901611f93565b94505060406121a988828901611fc6565b935050606086013567ffffffffffffffff8111156121ca576121c9611e63565b5b6121d68882890161210c565b92509250509295509295909350565b6121ee81611e67565b82525050565b5f6020820190506122075f8301846121e5565b92915050565b5f8083601f84011261222257612221612100565b5b8235905067ffffffffffffffff81111561223f5761223e612104565b5b60208301915083602082028301111561225b5761225a612108565b5b9250929050565b5f805f805f805f8060a0898b03121561227e5761227d611e5f565b5b5f61228b8b828c01611f93565b985050602061229c8b828c01611f93565b975050604089013567ffffffffffffffff8111156122bd576122bc611e63565b5b6122c98b828c0161220d565b9650965050606089013567ffffffffffffffff8111156122ec576122eb611e63565b5b6122f88b828c0161220d565b9450945050608089013567ffffffffffffffff81111561231b5761231a611e63565b5b6123278b828c0161210c565b92509250509295985092959890939650565b5f6020828403121561234e5761234d611e5f565b5b5f61235b84828501611f39565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b61239881612364565b82525050565b5f63ffffffff82169050919050565b6123b68161239e565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600481106123fa576123f96123bc565b5b50565b5f81905061240a826123e9565b919050565b5f612419826123fd565b9050919050565b6124298161240f565b82525050565b5f6060820190506124425f83018661238f565b61244f60208301856123ad565b61245c6040830184612420565b949350505050565b5f805f805f8060a0878903121561247e5761247d611e5f565b5b5f61248b89828a01611f93565b965050602061249c89828a01611f93565b95505060406124ad89828a01611fc6565b94505060606124be89828a01611fc6565b935050608087013567ffffffffffffffff8111156124df576124de611e63565b5b6124eb89828a0161210c565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f612564602a836124fa565b915061256f8261250a565b604082019050919050565b5f6020820190508181035f83015261259181612558565b9050919050565b5f819050919050565b6125b26125ad82611f1a565b612598565b82525050565b5f6125c382846125a1565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6125fe826125d2565b61260881856125dc565b93506126188185602086016125e6565b80840191505092915050565b5f61262f82846125f4565b915081905092915050565b5f8151905061264881611f23565b92915050565b5f6020828403121561266357612662611e5f565b5b5f6126708482850161263a565b91505092915050565b5f8160601b9050919050565b5f61268f82612679565b9050919050565b5f6126a082612685565b9050919050565b6126b86126b382611f6c565b612696565b82525050565b5f819050919050565b6126d86126d382611fa7565b6126be565b82525050565b5f6126e9828a6126a7565b6014820191506126f982896126a7565b60148201915061270982886125a1565b60208201915061271982876125a1565b60208201915061272982866126a7565b60148201915061273982856126c7565b60208201915061274982846126c7565b60208201915081905098975050505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f6127926013836124fa565b915061279d8261275e565b602082019050919050565b5f6020820190508181035f8301526127bf81612786565b9050919050565b6127cf81611f1a565b82525050565b5f6020820190506127e85f8301846127c6565b92915050565b6127f781611f6c565b82525050565b61280681611fa7565b82525050565b5f82825260208201905092915050565b50565b5f61282a5f8361280c565b91506128358261281c565b5f82019050919050565b5f60a0820190506128525f8301876127ee565b61285f60208301866127ee565b61286c60408301856127fd565b61287960608301846127fd565b818103608083015261288a8161281f565b905095945050505050565b5f6128a082896126a7565b6014820191506128b082886126a7565b6014820191506128c082876125a1565b6020820191506128d082866125a1565b6020820191506128e082856126a7565b6014820191506128f082846126c7565b602082019150819050979650505050505050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f61295e6038836124fa565b915061296982612904565b604082019050919050565b5f6020820190508181035f83015261298b81612952565b9050919050565b5f6060820190506129a55f8301866127ee565b6129b260208301856127ee565b6129bf60408301846127fd565b949350505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612a11826129cb565b810181811067ffffffffffffffff82111715612a3057612a2f6129db565b5b80604052505050565b5f612a42611e56565b9050612a4e8282612a08565b919050565b612a5c8161239e565b8114612a66575f80fd5b50565b5f81359050612a7781612a53565b92915050565b5f60c08284031215612a9257612a916129c7565b5b612a9c60c0612a39565b90505f612aab84828501611f39565b5f830152506020612abe84828501611f93565b6020830152506040612ad284828501611f93565b6040830152506060612ae684828501611f39565b6060830152506080612afa84828501611f39565b60808301525060a0612b0e84828501612a69565b60a08301525092915050565b5f60c08284031215612b2f57612b2e611e5f565b5b5f612b3c84828501612a7d565b91505092915050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f612b9f602a836124fa565b9150612baa82612b45565b604082019050919050565b5f6020820190508181035f830152612bcc81612b93565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f612c07601e836124fa565b9150612c1282612bd3565b602082019050919050565b5f6020820190508181035f830152612c3481612bfb565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f612c6f601e836124fa565b9150612c7a82612c3b565b602082019050919050565b5f6020820190508181035f830152612c9c81612c63565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f612cfd6023836124fa565b9150612d0882612ca3565b604082019050919050565b5f6020820190508181035f830152612d2a81612cf1565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f612d65601b836124fa565b9150612d7082612d31565b602082019050919050565b5f6020820190508181035f830152612d9281612d59565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f612dcd601a836124fa565b9150612dd882612d99565b602082019050919050565b5f6020820190508181035f830152612dfa81612dc1565b9050919050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f612e35601d836124fa565b9150612e4082612e01565b602082019050919050565b5f6020820190508181035f830152612e6281612e29565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f612e9d6015836124fa565b9150612ea882612e69565b602082019050919050565b5f6020820190508181035f830152612eca81612e91565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f612f2b602b836124fa565b9150612f3682612ed1565b604082019050919050565b5f6020820190508181035f830152612f5881612f1f565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f612f93601c836124fa565b9150612f9e82612f5f565b602082019050919050565b5f6020820190508181035f830152612fc081612f87565b905091905056fea26469706673582212208adfd9bc3010e8e9bf1d503f3e439ea5632ee575d696af59d80e0a2268d48d7e64736f6c634300081a0033 \ No newline at end of file diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index e650ef4293..57084a72e2 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -828,6 +828,13 @@ pub fn erc20_dev_conf(contract_address: &str) -> Json { }) } +/// ERC20 token configuration used for dockerized tests on Sepolia +pub fn sepolia_erc20_dev_conf(contract_address: &str) -> Json { + let mut conf = erc20_dev_conf(contract_address); + set_chain_id(&mut conf, ETH_SEPOLIA_CHAIN_ID); + conf +} + /// global NFT configuration used for dockerized Geth dev node pub fn nft_dev_conf() -> Json { json!({ @@ -846,21 +853,8 @@ pub fn nft_dev_conf() -> Json { }) } -/// global NFT configuration used for Sepolia testnet -pub fn nft_sepolia_conf() -> Json { - json!({ - "coin": "NFT_ETH", - "name": "nftdev", - "chain_id": 11155111, - "mm2": 1, - "derivation_path": "m/44'/60'", - "protocol": { - "type": "NFT", - "protocol_data": { - "platform": "ETH" - } - } - }) +fn set_chain_id(conf: &mut Json, chain_id: u64) { + conf["chain_id"] = json!(chain_id); } pub fn eth_sepolia_conf() -> Json { @@ -868,7 +862,7 @@ pub fn eth_sepolia_conf() -> Json { "coin": "ETH", "name": "ethereum", "derivation_path": "m/44'/60'", - "chain_id": 11155111, + "chain_id": ETH_SEPOLIA_CHAIN_ID, "protocol": { "type": "ETH" }, @@ -882,7 +876,7 @@ pub fn eth_sepolia_trezor_firmware_compat_conf() -> Json { "coin": "tETH", "name": "ethereum", "derivation_path": "m/44'/1'", // Note: trezor uses coin type 1' for eth for testnet (SLIP44_TESTNET) - "chain_id": 11155111, + "chain_id": ETH_SEPOLIA_CHAIN_ID, "protocol": { "type": "ETH" }, @@ -912,12 +906,12 @@ pub fn jst_sepolia_conf() -> Json { json!({ "coin": "JST", "name": "jst", - "chain_id": 11155111, + "chain_id": ETH_SEPOLIA_CHAIN_ID, "protocol": { "type": "ERC20", "protocol_data": { "platform": "ETH", - "chain_id": 11155111, + "chain_id": ETH_SEPOLIA_CHAIN_ID, "contract_address": ETH_SEPOLIA_TOKEN_CONTRACT } }, @@ -929,14 +923,14 @@ pub fn jst_sepolia_trezor_conf() -> Json { json!({ "coin": "tJST", "name": "tjst", - "chain_id": 11155111, + "chain_id": ETH_SEPOLIA_CHAIN_ID, "derivation_path": "m/44'/1'", // Note: Trezor uses 1' coin type for all testnets "trezor_coin": "tETH", "protocol": { "type": "ERC20", "protocol_data": { "platform": "ETH", - "chain_id": 11155111, + "chain_id": ETH_SEPOLIA_CHAIN_ID, "contract_address": ETH_SEPOLIA_TOKEN_CONTRACT } } diff --git a/mm2src/proxy_signature/src/lib.rs b/mm2src/proxy_signature/src/lib.rs index 86f57a3431..f4ae2393a0 100644 --- a/mm2src/proxy_signature/src/lib.rs +++ b/mm2src/proxy_signature/src/lib.rs @@ -74,7 +74,9 @@ impl ProxySign { return false; } - let Ok(public_key) = PublicKey::try_decode_protobuf(&self.raw_message.public_key_encoded) else { return false }; + let Ok(public_key) = PublicKey::try_decode_protobuf(&self.raw_message.public_key_encoded) else { + return false; + }; if self.address != public_key.to_peer_id().to_string() { return false; From 805ed93f797390d19343446f2e7abea6d9c3f6d3 Mon Sep 17 00:00:00 2001 From: Alrighttt <36680730+Alrighttt@users.noreply.github.com> Date: Fri, 30 Aug 2024 07:09:19 -0400 Subject: [PATCH 04/15] feat(sia): extract sia lib to external repo (#2167) This comit removes any sia lib related code from kdf and uses sia-rust repo as a dependency instead. `my_balance` is also implemented for siacoin in this commit. --- Cargo.lock | 28 ++ mm2src/coins/Cargo.toml | 9 +- mm2src/coins/hd_wallet/pubkey.rs | 9 + mm2src/coins/lp_coins.rs | 8 +- mm2src/coins/sia/address.rs | 167 --------- mm2src/coins/sia/blake2b_internal.rs | 326 ------------------ mm2src/coins/sia/encoding.rs | 119 ------- mm2src/coins/sia/http_client.rs | 208 ----------- mm2src/coins/sia/spend_policy.rs | 322 ----------------- mm2src/coins/{sia.rs => siacoin.rs} | 109 ++++-- mm2src/coins/siacoin/sia_hd_wallet.rs | 44 +++ mm2src/coins_activation/src/prelude.rs | 2 +- .../src/sia_coin_activation.rs | 4 +- mm2src/mm2_main/Cargo.toml | 6 +- .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 2 +- .../tests/docker_tests/docker_tests_common.rs | 20 ++ mm2src/mm2_main/tests/docker_tests/mod.rs | 1 + .../tests/docker_tests/sia_docker_tests.rs | 118 +++++++ mm2src/mm2_main/tests/docker_tests_main.rs | 1 + .../mm2_main/tests/docker_tests_sia_unique.rs | 106 ++++++ 20 files changed, 424 insertions(+), 1185 deletions(-) delete mode 100644 mm2src/coins/sia/address.rs delete mode 100644 mm2src/coins/sia/blake2b_internal.rs delete mode 100644 mm2src/coins/sia/encoding.rs delete mode 100644 mm2src/coins/sia/http_client.rs delete mode 100644 mm2src/coins/sia/spend_policy.rs rename mm2src/coins/{sia.rs => siacoin.rs} (84%) create mode 100644 mm2src/coins/siacoin/sia_hd_wallet.rs create mode 100644 mm2src/mm2_main/tests/docker_tests/sia_docker_tests.rs create mode 100644 mm2src/mm2_main/tests/docker_tests_sia_unique.rs diff --git a/Cargo.lock b/Cargo.lock index 681184de65..431959e5c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1026,6 +1026,7 @@ dependencies = [ "bytes 0.4.12", "cfg-if 1.0.0", "chain", + "chrono", "common", "cosmrs", "crossbeam 0.8.2", @@ -1077,6 +1078,7 @@ dependencies = [ "mm2_state_machine", "mm2_test_helpers", "mocktopus", + "nom", "num-traits", "parking_lot 0.12.0", "primitives", @@ -1102,10 +1104,12 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "serde_with", "serialization", "serialization_derive", "sha2 0.10.7", "sha3 0.9.1", + "sia-rust", "solana-client", "solana-sdk", "solana-transaction-status", @@ -2019,6 +2023,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" dependencies = [ + "serde", "signature 1.4.0", ] @@ -2055,6 +2060,7 @@ dependencies = [ "ed25519 1.5.2", "rand 0.7.3", "serde", + "serde_bytes", "sha2 0.9.9", "zeroize", ] @@ -4617,6 +4623,7 @@ dependencies = [ "serde_json", "serialization", "serialization_derive", + "sia-rust", "sp-runtime-interface", "sp-trie", "spv_validation", @@ -4624,6 +4631,7 @@ dependencies = [ "tokio", "trie-db", "trie-root 0.16.0", + "url", "uuid 1.2.2", "wasm-bindgen", "wasm-bindgen-futures", @@ -7011,6 +7019,26 @@ dependencies = [ "log", ] +[[package]] +name = "sia-rust" +version = "0.1.0" +source = "git+https://github.com/KomodoPlatform/sia-rust?rev=9f188b80b3213bcb604e7619275251ce08fae808#9f188b80b3213bcb604e7619275251ce08fae808" +dependencies = [ + "base64 0.21.7", + "blake2b_simd", + "chrono", + "derive_more", + "ed25519-dalek", + "hex", + "nom", + "reqwest", + "rustc-hex", + "serde", + "serde_json", + "serde_with", + "url", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index 3f37c3d74e..c5eeb570ea 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -18,7 +18,8 @@ enable-solana = [ ] enable-sia = [ "dep:reqwest", - "blake2b_simd" + "dep:blake2b_simd", + "dep:sia-rust" ] default = [] run-docker-tests = [] @@ -41,13 +42,14 @@ byteorder = "1.3" bytes = "0.4" cfg-if = "1.0" chain = { path = "../mm2_bitcoin/chain" } +chrono = { version = "0.4.23", "features" = ["serde"] } common = { path = "../common" } cosmrs = { version = "0.14.0", default-features = false } crossbeam = "0.8" crypto = { path = "../crypto" } db_common = { path = "../db_common" } derive_more = "0.99" -ed25519-dalek = "1.0.1" +ed25519-dalek = { version = "1.0.1", features = ["serde"] } enum_derives = { path = "../derives/enum_derives" } ethabi = { version = "17.0.0" } ethcore-transaction = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git", rev = "mm2-v2.1.1" } @@ -69,6 +71,7 @@ jsonrpc-core = "18.0.0" keys = { path = "../mm2_bitcoin/keys" } lazy_static = "1.4" libc = "0.2" +nom = "6.1.2" mm2_core = { path = "../mm2_core" } mm2_err_handle = { path = "../mm2_err_handle" } mm2_event_stream = { path = "../mm2_event_stream" } @@ -101,8 +104,10 @@ ser_error_derive = { path = "../derives/ser_error_derive" } serde = "1.0" serde_derive = "1.0" serde_json = { version = "1", features = ["preserve_order", "raw_value"] } +serde_with = "1.14.0" serialization = { path = "../mm2_bitcoin/serialization" } serialization_derive = { path = "../mm2_bitcoin/serialization_derive" } +sia-rust = { git = "https://github.com/KomodoPlatform/sia-rust", rev = "9f188b80b3213bcb604e7619275251ce08fae808", optional = true } spv_validation = { path = "../mm2_bitcoin/spv_validation" } sha2 = "0.10" sha3 = "0.9" diff --git a/mm2src/coins/hd_wallet/pubkey.rs b/mm2src/coins/hd_wallet/pubkey.rs index 7732819295..7babb12bd5 100644 --- a/mm2src/coins/hd_wallet/pubkey.rs +++ b/mm2src/coins/hd_wallet/pubkey.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "enable-sia")] +use crate::siacoin::sia_hd_wallet::Ed25519ExtendedPublicKey; use crate::CoinProtocol; use super::*; @@ -30,6 +32,13 @@ impl ExtendedPublicKeyOps for Secp256k1ExtendedPublicKey { fn to_string(&self, prefix: Prefix) -> String { self.to_string(prefix) } } +#[cfg(feature = "enable-sia")] +impl ExtendedPublicKeyOps for Ed25519ExtendedPublicKey { + fn derive_child(&self, child_number: ChildNumber) -> Result { self.derive_child(child_number) } + + fn to_string(&self, prefix: Prefix) -> String { self.to_string(prefix) } +} + /// This trait should be implemented for coins /// to support extracting extended public keys from any depth. /// The extraction can be from either an internal or external wallet. diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 8ca714a34f..1af6027e30 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -240,7 +240,7 @@ use coin_errors::{MyAddressError, ValidatePaymentError, ValidatePaymentFut, Vali pub mod coins_tests; pub mod eth; -use eth::eth_swap_v2::{PaymentStatusErr, ValidatePaymentV2Err}; +use eth::eth_swap_v2::{PaymentStatusErr, PrepareTxDataError, ValidatePaymentV2Err}; use eth::GetValidEthWithdrawAddError; use eth::{eth_coin_from_conf_and_request, get_eth_address, EthCoin, EthGasDetailsErr, EthTxFeeDetails, GetEthAddressError, SignedEthTx}; @@ -277,6 +277,9 @@ pub use test_coin::TestCoin; pub mod tx_history_storage; +#[cfg(feature = "enable-sia")] pub mod siacoin; +#[cfg(feature = "enable-sia")] use siacoin::SiaCoin; + #[doc(hidden)] #[allow(unused_variables)] #[cfg(all( @@ -319,9 +322,6 @@ use script::Script; pub mod z_coin; use crate::coin_balance::{BalanceObjectOps, HDWalletBalanceObject}; use z_coin::{ZCoin, ZcoinProtocolInfo}; -#[cfg(feature = "enable-sia")] pub mod sia; -use crate::eth::eth_swap_v2::PrepareTxDataError; -#[cfg(feature = "enable-sia")] use sia::SiaCoin; pub type TransactionFut = Box + Send>; pub type TransactionResult = Result; diff --git a/mm2src/coins/sia/address.rs b/mm2src/coins/sia/address.rs deleted file mode 100644 index 5218a08bc8..0000000000 --- a/mm2src/coins/sia/address.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::sia::blake2b_internal::standard_unlock_hash; -use blake2b_simd::Params; -use ed25519_dalek::PublicKey; -use hex::FromHexError; -use rpc::v1::types::H256; -use serde::{Deserialize, Serialize}; -use std::convert::TryInto; -use std::fmt; -use std::str::FromStr; - -// TODO this could probably include the checksum within the data type -// generating the checksum on the fly is how Sia Go does this however -#[derive(Debug, Clone, PartialEq)] -pub struct Address(pub H256); - -impl Address { - pub fn str_without_prefix(&self) -> String { - let bytes = self.0 .0.as_ref(); - let checksum = blake2b_checksum(bytes); - format!("{}{}", hex::encode(bytes), hex::encode(checksum)) - } -} - -impl fmt::Display for Address { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "addr:{}", self.str_without_prefix()) } -} - -impl fmt::Display for ParseAddressError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Failed to parse Address: {:?}", self) } -} - -#[derive(Debug, Deserialize, Serialize)] -pub enum ParseAddressError { - #[serde(rename = "Address must begin with addr: prefix")] - MissingPrefix, - InvalidHexEncoding(String), - InvalidChecksum, - InvalidLength, - // Add other error kinds as needed -} - -impl From for ParseAddressError { - fn from(e: FromHexError) -> Self { ParseAddressError::InvalidHexEncoding(e.to_string()) } -} - -impl FromStr for Address { - type Err = ParseAddressError; - - fn from_str(s: &str) -> Result { - if !s.starts_with("addr:") { - return Err(ParseAddressError::MissingPrefix); - } - - let without_prefix = &s[5..]; - if without_prefix.len() != (32 + 6) * 2 { - return Err(ParseAddressError::InvalidLength); - } - - let (address_hex, checksum_hex) = without_prefix.split_at(32 * 2); - - let address_bytes: [u8; 32] = hex::decode(address_hex) - .map_err(ParseAddressError::from)? - .try_into() - .expect("length is 32 bytes"); - - let checksum = hex::decode(checksum_hex).map_err(ParseAddressError::from)?; - let checksum_bytes: [u8; 6] = checksum.try_into().expect("length is 6 bytes"); - - if checksum_bytes != blake2b_checksum(&address_bytes) { - return Err(ParseAddressError::InvalidChecksum); - } - - Ok(Address(H256::from(address_bytes))) - } -} - -// Sia uses the first 6 bytes of blake2b(preimage) appended -// to address as checksum -fn blake2b_checksum(preimage: &[u8]) -> [u8; 6] { - let hash = Params::new().hash_length(32).to_state().update(preimage).finalize(); - hash.as_array()[0..6].try_into().expect("array is 64 bytes long") -} - -pub fn v1_standard_address_from_pubkey(pubkey: &PublicKey) -> Address { - let hash = standard_unlock_hash(pubkey); - Address(hash) -} - -#[test] -fn test_v1_standard_address_from_pubkey() { - let pubkey = PublicKey::from_bytes( - &hex::decode("8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c").unwrap(), - ) - .unwrap(); - let address = v1_standard_address_from_pubkey(&pubkey); - assert_eq!( - format!("{}", address), - "addr:c959f9b423b662c36ee58057b8157acedb4095cfeb7926e4ba44cd9ee1f49a5b7803c7501a7b" - ) -} - -#[test] -fn test_blake2b_checksum() { - let checksum = - blake2b_checksum(&hex::decode("591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a884").unwrap()); - let expected: [u8; 6] = hex::decode("0be0653e411f").unwrap().try_into().unwrap(); - assert_eq!(checksum, expected); -} - -#[test] -fn test_address_display() { - let address = Address("591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a884".into()); - let address_str = "addr:591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a8840be0653e411f"; - assert_eq!(format!("{}", address), address_str); -} - -#[test] -fn test_address_fromstr() { - let address1 = Address("591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a884".into()); - - let address2 = - Address::from_str("addr:591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a8840be0653e411f").unwrap(); - assert_eq!(address1, address2); -} - -#[test] -fn test_address_fromstr_bad_length() { - let address = Address::from_str("addr:dead"); - assert!(matches!(address, Err(ParseAddressError::InvalidLength))); -} - -#[test] -fn test_address_fromstr_odd_length() { - let address = Address::from_str("addr:f00"); - assert!(matches!(address, Err(ParseAddressError::InvalidLength))); -} - -#[test] -fn test_address_fromstr_invalid_hex() { - let address = - Address::from_str("addr:591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a8840be0653e41gg"); - assert!(matches!(address, Err(ParseAddressError::InvalidHexEncoding(_)))); -} - -#[test] -fn test_address_fromstr_missing_prefix() { - let address = Address::from_str("591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a8840be0653e41gg"); - assert!(matches!(address, Err(ParseAddressError::MissingPrefix))); -} - -#[test] -fn test_address_fromstr_invalid_checksum() { - let address = - Address::from_str("addr:591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a884ffffffffffff"); - assert!(matches!(address, Err(ParseAddressError::InvalidChecksum))); -} - -#[test] -fn test_address_str_without_prefix() { - let address = - Address::from_str("addr:591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a8840be0653e411f").unwrap(); - - assert_eq!( - address.str_without_prefix(), - "591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a8840be0653e411f" - ); -} diff --git a/mm2src/coins/sia/blake2b_internal.rs b/mm2src/coins/sia/blake2b_internal.rs deleted file mode 100644 index 39c4f7c82b..0000000000 --- a/mm2src/coins/sia/blake2b_internal.rs +++ /dev/null @@ -1,326 +0,0 @@ -use blake2b_simd::Params; -use ed25519_dalek::PublicKey; -use rpc::v1::types::H256; -use std::default::Default; - -#[cfg(test)] use hex; -#[cfg(test)] use std::convert::TryInto; - -const LEAF_HASH_PREFIX: [u8; 1] = [0u8]; -const NODE_HASH_PREFIX: [u8; 1] = [1u8]; - -pub const ED25519_IDENTIFIER: [u8; 16] = [ - 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -]; - -// Precomputed hash values used for all standard v1 addresses -// a standard address has 1 ed25519 public key, requires 1 signature and has a timelock of 0 -// https://github.com/SiaFoundation/core/blob/b5b08cde6b7d0f1b3a6f09b8aa9d0b817e769efb/types/hash.go#L94 -const STANDARD_TIMELOCK_BLAKE2B_HASH: [u8; 32] = [ - 0x51, 0x87, 0xb7, 0xa8, 0x02, 0x1b, 0xf4, 0xf2, 0xc0, 0x04, 0xea, 0x3a, 0x54, 0xcf, 0xec, 0xe1, 0x75, 0x4f, 0x11, - 0xc7, 0x62, 0x4d, 0x23, 0x63, 0xc7, 0xf4, 0xcf, 0x4f, 0xdd, 0xd1, 0x44, 0x1e, -]; - -const STANDARD_SIGS_REQUIRED_BLAKE2B_HASH: [u8; 32] = [ - 0xb3, 0x60, 0x10, 0xeb, 0x28, 0x5c, 0x15, 0x4a, 0x8c, 0xd6, 0x30, 0x84, 0xac, 0xbe, 0x7e, 0xac, 0x0c, 0x4d, 0x62, - 0x5a, 0xb4, 0xe1, 0xa7, 0x6e, 0x62, 0x4a, 0x87, 0x98, 0xcb, 0x63, 0x49, 0x7b, -]; - -#[derive(Debug, PartialEq)] -pub struct Accumulator { - trees: [H256; 64], - num_leaves: u64, -} - -impl Default for Accumulator { - fn default() -> Self { - Accumulator { - trees: [H256::default(); 64], // Initialize all bytes to zero - num_leaves: 0, - } - } -} - -impl Accumulator { - // Check if there is a tree at the given height - fn has_tree_at_height(&self, height: u64) -> bool { self.num_leaves & (1 << height) != 0 } - - // Add a leaf to the accumulator - pub fn add_leaf(&mut self, h: H256) { - let mut i = 0; - let mut new_hash = h; - while self.has_tree_at_height(i) { - new_hash = hash_blake2b_pair(&NODE_HASH_PREFIX, &self.trees[i as usize].0, &new_hash.0); - i += 1; - } - self.trees[i as usize] = new_hash; - self.num_leaves += 1; - } - - // Calulate the root hash of the Merkle tree - pub fn root(&self) -> H256 { - // trailing_zeros determines the height Merkle tree accumulator where the current lowest single leaf is located - let i = self.num_leaves.trailing_zeros() as u64; - if i == 64 { - return H256::default(); // Return all zeros if no leaves - } - let mut root = self.trees[i as usize]; - for j in i + 1..64 { - if self.has_tree_at_height(j) { - root = hash_blake2b_pair(&NODE_HASH_PREFIX, &self.trees[j as usize].0, &root.0); - } - } - root - } -} - -pub fn sigs_required_leaf(sigs_required: u64) -> H256 { - let sigs_required_array: [u8; 8] = sigs_required.to_le_bytes(); - let mut combined = Vec::new(); - combined.extend_from_slice(&LEAF_HASH_PREFIX); - combined.extend_from_slice(&sigs_required_array); - - hash_blake2b_single(&combined) -} - -// public key leaf is -// blake2b(leafHashPrefix + 16_byte_ascii_algorithm_identifier + public_key_length_u64 + public_key) -pub fn public_key_leaf(pubkey: &PublicKey) -> H256 { - let mut combined = Vec::new(); - combined.extend_from_slice(&LEAF_HASH_PREFIX); - combined.extend_from_slice(&ED25519_IDENTIFIER); - combined.extend_from_slice(&32u64.to_le_bytes()); - combined.extend_from_slice(pubkey.as_bytes()); - hash_blake2b_single(&combined) -} - -pub fn timelock_leaf(timelock: u64) -> H256 { - let timelock: [u8; 8] = timelock.to_le_bytes(); - let mut combined = Vec::new(); - combined.extend_from_slice(&LEAF_HASH_PREFIX); - combined.extend_from_slice(&timelock); - - hash_blake2b_single(&combined) -} - -// https://github.com/SiaFoundation/core/blob/b5b08cde6b7d0f1b3a6f09b8aa9d0b817e769efb/types/hash.go#L96 -// An UnlockHash is the Merkle root of UnlockConditions. Since the standard -// UnlockConditions use a single public key, the Merkle tree is: -// -// ┌─────────┴──────────┐ -// ┌─────┴─────┐ │ -// timelock pubkey sigsrequired -pub fn standard_unlock_hash(pubkey: &PublicKey) -> H256 { - let pubkey_leaf = public_key_leaf(pubkey); - let timelock_pubkey_node = hash_blake2b_pair(&NODE_HASH_PREFIX, &STANDARD_TIMELOCK_BLAKE2B_HASH, &pubkey_leaf.0); - hash_blake2b_pair( - &NODE_HASH_PREFIX, - &timelock_pubkey_node.0, - &STANDARD_SIGS_REQUIRED_BLAKE2B_HASH, - ) -} - -pub fn hash_blake2b_single(preimage: &[u8]) -> H256 { - let hash = Params::new().hash_length(32).to_state().update(preimage).finalize(); - let ret_array = hash.as_array(); - ret_array[0..32].into() -} - -fn hash_blake2b_pair(prefix: &[u8], leaf1: &[u8], leaf2: &[u8]) -> H256 { - let hash = Params::new() - .hash_length(32) - .to_state() - .update(prefix) - .update(leaf1) - .update(leaf2) - .finalize(); - let ret_array = hash.as_array(); - ret_array[0..32].into() -} - -#[test] -fn test_accumulator_new() { - let default_accumulator = Accumulator::default(); - - let expected = Accumulator { - trees: [H256::from("0000000000000000000000000000000000000000000000000000000000000000"); 64], - num_leaves: 0, - }; - assert_eq!(default_accumulator, expected) -} - -#[test] -fn test_accumulator_root_default() { assert_eq!(Accumulator::default().root(), H256::default()) } - -#[test] -fn test_accumulator_root() { - let mut accumulator = Accumulator::default(); - - let timelock_leaf = timelock_leaf(0u64); - accumulator.add_leaf(timelock_leaf); - - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let pubkey_leaf = public_key_leaf(&pubkey); - accumulator.add_leaf(pubkey_leaf); - - let sigs_required_leaf = sigs_required_leaf(1u64); - accumulator.add_leaf(sigs_required_leaf); - - let expected = H256::from("72b0762b382d4c251af5ae25b6777d908726d75962e5224f98d7f619bb39515d"); - assert_eq!(accumulator.root(), expected); -} - -#[test] -fn test_accumulator_add_leaf_standard_unlock_hash() { - let mut accumulator = Accumulator::default(); - - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - - let pubkey_leaf = public_key_leaf(&pubkey); - let timelock_leaf = timelock_leaf(0u64); - let sigs_required_leaf = sigs_required_leaf(1u64); - - accumulator.add_leaf(timelock_leaf); - accumulator.add_leaf(pubkey_leaf); - accumulator.add_leaf(sigs_required_leaf); - - let root = accumulator.root(); - let expected = H256::from("72b0762b382d4c251af5ae25b6777d908726d75962e5224f98d7f619bb39515d"); - assert_eq!(root, expected) -} - -#[test] -fn test_accumulator_add_leaf_2of2_multisig_unlock_hash() { - let mut accumulator = Accumulator::default(); - - let pubkey1 = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let pubkey2 = PublicKey::from_bytes( - &hex::decode("0101010000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - - let pubkey1_leaf = public_key_leaf(&pubkey1); - let pubkey2_leaf = public_key_leaf(&pubkey2); - - let timelock_leaf = timelock_leaf(0u64); - let sigs_required_leaf = sigs_required_leaf(2u64); - - accumulator.add_leaf(timelock_leaf); - accumulator.add_leaf(pubkey1_leaf); - accumulator.add_leaf(pubkey2_leaf); - accumulator.add_leaf(sigs_required_leaf); - - let root = accumulator.root(); - let expected = H256::from("1e94357817d236167e54970a8c08bbd41b37bfceeeb52f6c1ce6dd01d50ea1e7"); - assert_eq!(root, expected) -} - -#[test] -fn test_accumulator_add_leaf_1of2_multisig_unlock_hash() { - let mut accumulator = Accumulator::default(); - - let pubkey1 = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let pubkey2 = PublicKey::from_bytes( - &hex::decode("0101010000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - - let pubkey1_leaf = public_key_leaf(&pubkey1); - let pubkey2_leaf = public_key_leaf(&pubkey2); - - let timelock_leaf = timelock_leaf(0u64); - let sigs_required_leaf = sigs_required_leaf(1u64); - - accumulator.add_leaf(timelock_leaf); - accumulator.add_leaf(pubkey1_leaf); - accumulator.add_leaf(pubkey2_leaf); - accumulator.add_leaf(sigs_required_leaf); - - let root = accumulator.root(); - let expected = H256::from("d7f84e3423da09d111a17f64290c8d05e1cbe4cab2b6bed49e3a4d2f659f0585"); - assert_eq!(root, expected) -} - -#[test] -fn test_standard_unlock_hash() { - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - - let hash = standard_unlock_hash(&pubkey); - let expected = H256::from("72b0762b382d4c251af5ae25b6777d908726d75962e5224f98d7f619bb39515d"); - assert_eq!(hash, expected) -} - -#[test] -fn test_hash_blake2b_pair() { - let left: [u8; 32] = hex::decode("cdcce3978a58ceb6c8480d218646db4eae85eb9ea9c2f5138fbacb4ce2c701e3") - .unwrap() - .try_into() - .unwrap(); - let right: [u8; 32] = hex::decode("b36010eb285c154a8cd63084acbe7eac0c4d625ab4e1a76e624a8798cb63497b") - .unwrap() - .try_into() - .unwrap(); - - let hash = hash_blake2b_pair(&NODE_HASH_PREFIX, &left, &right); - let expected = H256::from("72b0762b382d4c251af5ae25b6777d908726d75962e5224f98d7f619bb39515d"); - assert_eq!(hash, expected) -} - -#[test] -fn test_create_ed25519_identifier() { - let mut ed25519_identifier: [u8; 16] = [0; 16]; - - let bytes = "ed25519".as_bytes(); - for (i, &byte) in bytes.iter().enumerate() { - ed25519_identifier[i] = byte; - } - assert_eq!(ed25519_identifier, ED25519_IDENTIFIER); -} - -#[test] -fn test_timelock_leaf() { - let hash = timelock_leaf(0); - let expected = H256::from(STANDARD_TIMELOCK_BLAKE2B_HASH); - assert_eq!(hash, expected) -} - -#[test] -fn test_sigs_required_leaf() { - let hash = sigs_required_leaf(1u64); - let expected = H256::from(STANDARD_SIGS_REQUIRED_BLAKE2B_HASH); - assert_eq!(hash, expected) -} - -#[test] -fn test_hash_blake2b_single() { - let hash = hash_blake2b_single(&hex::decode("006564323535313900000000000000000020000000000000000102030000000000000000000000000000000000000000000000000000000000").unwrap()); - let expected = H256::from("21ce940603a2ee3a283685f6bfb4b122254894fd1ed3eb59434aadbf00c75d5b"); - assert_eq!(hash, expected) -} - -#[test] -fn test_public_key_leaf() { - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - - let hash = public_key_leaf(&pubkey); - let expected = H256::from("21ce940603a2ee3a283685f6bfb4b122254894fd1ed3eb59434aadbf00c75d5b"); - assert_eq!(hash, expected) -} diff --git a/mm2src/coins/sia/encoding.rs b/mm2src/coins/sia/encoding.rs deleted file mode 100644 index 5b6516101a..0000000000 --- a/mm2src/coins/sia/encoding.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::sia::blake2b_internal::hash_blake2b_single; -use rpc::v1::types::H256; - -// https://github.com/SiaFoundation/core/blob/092850cc52d3d981b19c66cd327b5d945b3c18d3/types/encoding.go#L16 -// TODO go implementation limits this to 1024 bytes, should we? -#[derive(Default)] -pub struct Encoder { - pub buffer: Vec, -} - -impl Encoder { - pub fn reset(&mut self) { self.buffer.clear(); } - - /// writes a length-prefixed []byte to the underlying stream. - pub fn write_len_prefixed_bytes(&mut self, data: &[u8]) { - self.buffer.extend_from_slice(&data.len().to_le_bytes()); - self.buffer.extend_from_slice(data); - } - - pub fn write_slice(&mut self, data: &[u8]) { self.buffer.extend_from_slice(data); } - - pub fn write_u8(&mut self, u: u8) { self.buffer.extend_from_slice(&[u]) } - - pub fn write_u64(&mut self, u: u64) { self.buffer.extend_from_slice(&u.to_le_bytes()); } - - pub fn write_distinguisher(&mut self, p: &str) { self.buffer.extend_from_slice(format!("sia/{}|", p).as_bytes()); } - - pub fn write_bool(&mut self, b: bool) { self.buffer.push(b as u8) } - - pub fn hash(&self) -> H256 { hash_blake2b_single(&self.buffer) } -} - -#[test] -fn test_encoder_default_hash() { - assert_eq!( - Encoder::default().hash(), - H256::from("0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8") - ) -} - -#[test] -fn test_encoder_write_bytes() { - let mut encoder = Encoder::default(); - encoder.write_len_prefixed_bytes(&[1, 2, 3, 4]); - assert_eq!( - encoder.hash(), - H256::from("d4a72b52e2e1f40e20ee40ea6d5080a1b1f76164786defbb7691a4427f3388f5") - ); -} - -#[test] -fn test_encoder_write_u8() { - let mut encoder = Encoder::default(); - encoder.write_u8(1); - assert_eq!( - encoder.hash(), - H256::from("ee155ace9c40292074cb6aff8c9ccdd273c81648ff1149ef36bcea6ebb8a3e25") - ); -} - -#[test] -fn test_encoder_write_u64() { - let mut encoder = Encoder::default(); - encoder.write_u64(1); - assert_eq!( - encoder.hash(), - H256::from("1dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b") - ); -} - -#[test] -fn test_encoder_write_distiguisher() { - let mut encoder = Encoder::default(); - encoder.write_distinguisher("test"); - assert_eq!( - encoder.hash(), - H256::from("25fb524721bf98a9a1233a53c40e7e198971b003bf23c24f59d547a1bb837f9c") - ); -} - -#[test] -fn test_encoder_write_bool() { - let mut encoder = Encoder::default(); - encoder.write_bool(true); - assert_eq!( - encoder.hash(), - H256::from("ee155ace9c40292074cb6aff8c9ccdd273c81648ff1149ef36bcea6ebb8a3e25") - ); -} - -#[test] -fn test_encoder_reset() { - let mut encoder = Encoder::default(); - encoder.write_bool(true); - assert_eq!( - encoder.hash(), - H256::from("ee155ace9c40292074cb6aff8c9ccdd273c81648ff1149ef36bcea6ebb8a3e25") - ); - - encoder.reset(); - encoder.write_bool(false); - assert_eq!( - encoder.hash(), - H256::from("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314") - ); -} - -#[test] -fn test_encoder_complex() { - let mut encoder = Encoder::default(); - encoder.write_distinguisher("test"); - encoder.write_bool(true); - encoder.write_u8(1); - encoder.write_len_prefixed_bytes(&[1, 2, 3, 4]); - assert_eq!( - encoder.hash(), - H256::from("b66d7a9bef9fb303fe0e41f6b5c5af410303e428c4ff9231f6eb381248693221") - ); -} diff --git a/mm2src/coins/sia/http_client.rs b/mm2src/coins/sia/http_client.rs deleted file mode 100644 index 774dcd08e1..0000000000 --- a/mm2src/coins/sia/http_client.rs +++ /dev/null @@ -1,208 +0,0 @@ -use crate::sia::address::Address; -use crate::sia::SiaHttpConf; -use base64::engine::general_purpose::STANDARD as BASE64; -use base64::Engine as _; // required for .encode() method -use core::fmt::Display; -use core::time::Duration; -use mm2_number::MmNumber; -use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION}; -use reqwest::{Client, Error, Url}; -use serde::de::DeserializeOwned; -use std::ops::Deref; -use std::sync::Arc; - -#[cfg(test)] use std::str::FromStr; - -const ENDPOINT_CONSENSUS_TIP: &str = "api/consensus/tip"; - -/// HTTP(s) client for Sia-protocol coins -#[derive(Debug)] -pub struct SiaHttpClientImpl { - /// Name of coin the http client is intended to work with - pub coin_ticker: String, - /// The uri to send requests to - pub uri: String, - /// Value of Authorization header password, e.g. "Basic base64(:password)" - pub auth: String, -} - -#[derive(Clone, Debug)] -pub struct SiaApiClient(pub Arc); - -impl Deref for SiaApiClient { - type Target = SiaApiClientImpl; - fn deref(&self) -> &SiaApiClientImpl { &self.0 } -} - -impl SiaApiClient { - pub fn new(_coin_ticker: &str, http_conf: SiaHttpConf) -> Result { - let new_arc = SiaApiClientImpl::new(http_conf.url, &http_conf.auth)?; - Ok(SiaApiClient(Arc::new(new_arc))) - } -} - -#[derive(Debug)] -pub struct SiaApiClientImpl { - client: Client, - base_url: Url, -} - -// this is neccesary to show the URL in error messages returned to the user -// this can be removed in favor of using ".with_url()" once reqwest is updated to v0.11.23 -#[derive(Debug)] -pub struct ReqwestErrorWithUrl { - error: Error, - url: Url, -} - -impl Display for ReqwestErrorWithUrl { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "Error: {}, URL: {}", self.error, self.url) - } -} - -#[derive(Debug, Display)] -pub enum SiaApiClientError { - Timeout(String), - BuildError(String), - ApiUnreachable(String), - ReqwestError(ReqwestErrorWithUrl), - UrlParse(url::ParseError), -} - -impl From for String { - fn from(e: SiaApiClientError) -> Self { format!("{:?}", e) } -} - -async fn fetch_and_parse(client: &Client, url: Url) -> Result { - client - .get(url.clone()) - .send() - .await - .map_err(|e| { - SiaApiClientError::ReqwestError(ReqwestErrorWithUrl { - error: e, - url: url.clone(), - }) - })? - .json::() - .await - .map_err(|e| SiaApiClientError::ReqwestError(ReqwestErrorWithUrl { error: e, url })) -} - -// https://github.com/SiaFoundation/core/blob/4e46803f702891e7a83a415b7fcd7543b13e715e/types/types.go#L181 -#[derive(Deserialize, Serialize, Debug)] -pub struct GetConsensusTipResponse { - pub height: u64, - pub id: String, // TODO this can match "BlockID" type -} - -// https://github.com/SiaFoundation/walletd/blob/9574e69ff0bf84de1235b68e78db2a41d5e27516/api/api.go#L36 -// https://github.com/SiaFoundation/walletd/blob/9574e69ff0bf84de1235b68e78db2a41d5e27516/wallet/wallet.go#L25 -#[derive(Deserialize, Serialize, Debug)] -pub struct GetAddressesBalanceResponse { - pub siacoins: MmNumber, - #[serde(rename = "immatureSiacoins")] - pub immature_siacoins: MmNumber, - pub siafunds: u64, -} - -impl SiaApiClientImpl { - fn new(base_url: Url, password: &str) -> Result { - let mut headers = HeaderMap::new(); - let auth_value = format!("Basic {}", BASE64.encode(format!(":{}", password))); - headers.insert( - AUTHORIZATION, - HeaderValue::from_str(&auth_value).map_err(|e| SiaApiClientError::BuildError(e.to_string()))?, - ); - - let client = Client::builder() - .default_headers(headers) - .timeout(Duration::from_secs(10)) // TODO make this configurable - .build() - .map_err(|e| { - SiaApiClientError::ReqwestError(ReqwestErrorWithUrl { - error: e, - url: base_url.clone(), - }) - })?; - Ok(SiaApiClientImpl { client, base_url }) - } - - pub async fn get_consensus_tip(&self) -> Result { - let base_url = self.base_url.clone(); - let endpoint_url = base_url - .join(ENDPOINT_CONSENSUS_TIP) - .map_err(SiaApiClientError::UrlParse)?; - - fetch_and_parse::(&self.client, endpoint_url).await - } - - pub async fn get_addresses_balance( - &self, - address: &Address, - ) -> Result { - self.get_addresses_balance_str(&address.str_without_prefix()).await - } - - // use get_addresses_balance whenever possible to rely on Address deserialization - pub async fn get_addresses_balance_str( - &self, - address: &str, - ) -> Result { - let base_url = self.base_url.clone(); - - let endpoint_path = format!("api/addresses/{}/balance", address); - let endpoint_url = base_url.join(&endpoint_path).map_err(SiaApiClientError::UrlParse)?; - - fetch_and_parse::(&self.client, endpoint_url).await - } - - pub async fn get_height(&self) -> Result { - let resp = self.get_consensus_tip().await?; - Ok(resp.height) - } -} - -#[tokio::test] -#[ignore] -async fn test_api_client_timeout() { - let api_client = SiaApiClientImpl::new(Url::parse("http://foo").unwrap(), "password").unwrap(); - let result = api_client.get_consensus_tip().await; - assert!(matches!(result, Err(SiaApiClientError::Timeout(_)))); -} - -// TODO all of the following must be adapted to use Docker Sia node -#[tokio::test] -#[ignore] -async fn test_api_client_invalid_auth() { - let api_client = SiaApiClientImpl::new(Url::parse("http://127.0.0.1:9980").unwrap(), "password").unwrap(); - let result = api_client.get_consensus_tip().await; - assert!(matches!(result, Err(SiaApiClientError::BuildError(_)))); -} - -// TODO must be adapted to use Docker Sia node -#[tokio::test] -#[ignore] -async fn test_api_client() { - let api_client = SiaApiClientImpl::new(Url::parse("http://127.0.0.1:9980").unwrap(), "password").unwrap(); - let _result = api_client.get_consensus_tip().await.unwrap(); -} - -#[tokio::test] -#[ignore] -async fn test_api_get_addresses_balance() { - let api_client = SiaApiClientImpl::new(Url::parse("http://127.0.0.1:9980").unwrap(), "password").unwrap(); - let address = - Address::from_str("addr:591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a8840be0653e411f").unwrap(); - let result = api_client.get_addresses_balance(&address).await.unwrap(); - println!("ret {:?}", result); -} - -#[tokio::test] -#[ignore] -async fn test_api_get_addresses_balance_invalid() { - let api_client = SiaApiClientImpl::new(Url::parse("http://127.0.0.1:9980").unwrap(), "password").unwrap(); - let result = api_client.get_addresses_balance_str("what").await.unwrap(); - println!("ret {:?}", result); -} diff --git a/mm2src/coins/sia/spend_policy.rs b/mm2src/coins/sia/spend_policy.rs deleted file mode 100644 index 6c28f7250a..0000000000 --- a/mm2src/coins/sia/spend_policy.rs +++ /dev/null @@ -1,322 +0,0 @@ -use crate::sia::address::Address; -use crate::sia::blake2b_internal::{public_key_leaf, sigs_required_leaf, standard_unlock_hash, timelock_leaf, - Accumulator, ED25519_IDENTIFIER}; -use crate::sia::encoding::Encoder; -use ed25519_dalek::PublicKey; -use rpc::v1::types::H256; - -#[cfg(test)] use std::str::FromStr; - -const POLICY_VERSION: u8 = 1u8; - -#[derive(Debug, Clone)] -pub enum SpendPolicy { - Above(u64), - After(u64), - PublicKey(PublicKey), - Hash(H256), - Threshold(PolicyTypeThreshold), - Opaque(Address), - UnlockConditions(PolicyTypeUnlockConditions), // For v1 compatibility -} - -impl SpendPolicy { - pub fn to_u8(&self) -> u8 { - match self { - SpendPolicy::Above(_) => 1, - SpendPolicy::After(_) => 2, - SpendPolicy::PublicKey(_) => 3, - SpendPolicy::Hash(_) => 4, - SpendPolicy::Threshold(_) => 5, - SpendPolicy::Opaque(_) => 6, - SpendPolicy::UnlockConditions(_) => 7, - } - } - - pub fn encode(&self) -> Encoder { - let mut encoder = Encoder::default(); - encoder.write_u8(POLICY_VERSION); - encoder.write_slice(&self.encode_wo_prefix().buffer); - encoder - } - - pub fn encode_wo_prefix(&self) -> Encoder { - let mut encoder = Encoder::default(); - let opcode = self.to_u8(); - match self { - SpendPolicy::Above(height) => { - encoder.write_u8(opcode); - encoder.write_u64(*height); - }, - SpendPolicy::After(time) => { - encoder.write_u8(opcode); - encoder.write_u64(*time); - }, - SpendPolicy::PublicKey(pubkey) => { - encoder.write_u8(opcode); - encoder.write_slice(&pubkey.to_bytes()); - }, - SpendPolicy::Hash(hash) => { - encoder.write_u8(opcode); - encoder.write_slice(&hash.0); - }, - SpendPolicy::Threshold(PolicyTypeThreshold { n, of }) => { - encoder.write_u8(opcode); - encoder.write_u8(*n); - encoder.write_u8(of.len() as u8); - for policy in of { - encoder.write_slice(&policy.encode_wo_prefix().buffer); - } - }, - SpendPolicy::Opaque(p) => { - encoder.write_u8(opcode); - encoder.write_slice(&p.0 .0); - }, - SpendPolicy::UnlockConditions(PolicyTypeUnlockConditions(unlock_condition)) => { - encoder.write_u8(opcode); - encoder.write_u64(unlock_condition.timelock); - encoder.write_u64(unlock_condition.pubkeys.len() as u64); - for pubkey in &unlock_condition.pubkeys { - encoder.write_slice(&ED25519_IDENTIFIER); - encoder.write_slice(&pubkey.to_bytes()); - } - encoder.write_u64(unlock_condition.sigs_required); - }, - } - encoder - } - - fn address(&self) -> Address { - if let SpendPolicy::UnlockConditions(PolicyTypeUnlockConditions(unlock_condition)) = self { - return unlock_condition.address(); - } - let mut encoder = Encoder::default(); - encoder.write_distinguisher("address"); - - // if self is a threshold policy, we need to convert all of its subpolicies to opaque - let mut new_policy = self.clone(); - if let SpendPolicy::Threshold(ref mut p) = new_policy { - p.of = p.of.iter().map(SpendPolicy::opaque).collect(); - } - - let encoded_policy = new_policy.encode(); - encoder.write_slice(&encoded_policy.buffer); - Address(encoder.hash()) - } - - pub fn above(height: u64) -> Self { SpendPolicy::Above(height) } - - pub fn after(time: u64) -> Self { SpendPolicy::After(time) } - - pub fn public_key(pk: PublicKey) -> Self { SpendPolicy::PublicKey(pk) } - - pub fn hash(h: H256) -> Self { SpendPolicy::Hash(h) } - - pub fn threshold(n: u8, of: Vec) -> Self { SpendPolicy::Threshold(PolicyTypeThreshold { n, of }) } - - pub fn opaque(p: &SpendPolicy) -> Self { SpendPolicy::Opaque(p.address()) } - - pub fn anyone_can_spend() -> Self { SpendPolicy::threshold(0, vec![]) } -} - -#[derive(Debug, Clone)] -pub struct PolicyTypeThreshold { - pub n: u8, - pub of: Vec, -} - -// Compatibility with Sia's "UnlockConditions" -#[derive(Debug, Clone)] -pub struct PolicyTypeUnlockConditions(UnlockCondition); - -#[derive(Debug, Clone)] -pub struct UnlockCondition { - pubkeys: Vec, - timelock: u64, - sigs_required: u64, -} - -impl UnlockCondition { - pub fn new(pubkeys: Vec, timelock: u64, sigs_required: u64) -> Self { - // TODO check go implementation to see if there should be limitations or checks imposed here - UnlockCondition { - pubkeys, - timelock, - sigs_required, - } - } - - pub fn unlock_hash(&self) -> H256 { - // almost all UnlockConditions are standard, so optimize for that case - if self.timelock == 0 && self.pubkeys.len() == 1 && self.sigs_required == 1 { - return standard_unlock_hash(&self.pubkeys[0]); - } - - let mut accumulator = Accumulator::default(); - - accumulator.add_leaf(timelock_leaf(self.timelock)); - - for pubkey in &self.pubkeys { - accumulator.add_leaf(public_key_leaf(pubkey)); - } - - accumulator.add_leaf(sigs_required_leaf(self.sigs_required)); - accumulator.root() - } - - pub fn address(&self) -> Address { Address(self.unlock_hash()) } -} - -#[test] -fn test_unlock_condition_unlock_hash_standard() { - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let unlock_condition = UnlockCondition::new(vec![pubkey], 0, 1); - - let hash = unlock_condition.unlock_hash(); - let expected = H256::from("72b0762b382d4c251af5ae25b6777d908726d75962e5224f98d7f619bb39515d"); - assert_eq!(hash, expected); - - let hash = standard_unlock_hash(&pubkey); - assert_eq!(hash, expected); -} - -#[test] -fn test_unlock_condition_unlock_hash_2of2_multisig() { - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let pubkey2 = PublicKey::from_bytes( - &hex::decode("0101010000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let unlock_condition = UnlockCondition::new(vec![pubkey, pubkey2], 0, 2); - - let hash = unlock_condition.unlock_hash(); - let expected = H256::from("1e94357817d236167e54970a8c08bbd41b37bfceeeb52f6c1ce6dd01d50ea1e7"); - assert_eq!(hash, expected); -} - -#[test] -fn test_unlock_condition_unlock_hash_1of2_multisig() { - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let pubkey2 = PublicKey::from_bytes( - &hex::decode("0101010000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let unlock_condition = UnlockCondition::new(vec![pubkey, pubkey2], 0, 1); - - let hash = unlock_condition.unlock_hash(); - let expected = H256::from("d7f84e3423da09d111a17f64290c8d05e1cbe4cab2b6bed49e3a4d2f659f0585"); - assert_eq!(hash, expected); -} - -#[test] -fn test_spend_policy_encode_above() { - let policy = SpendPolicy::above(1); - - let hash = policy.encode().hash(); - let expected = H256::from("bebf6cbdfb440a92e3e5d832ac30fe5d226ff6b352ed3a9398b7d35f086a8ab6"); - assert_eq!(hash, expected); - - let address = policy.address(); - let expected = - Address::from_str("addr:188b997bb99dee13e95f92c3ea150bd76b3ec72e5ba57b0d57439a1a6e2865e9b25ea5d1825e").unwrap(); - assert_eq!(address, expected); -} - -#[test] -fn test_spend_policy_encode_after() { - let policy = SpendPolicy::after(1); - - let hash = policy.encode().hash(); - let expected = H256::from("07b0f28eafd87a082ad11dc4724e1c491821260821a30bec68254444f97d9311"); - assert_eq!(hash, expected); - - let address = policy.address(); - let expected = - Address::from_str("addr:60c74e0ce5cede0f13f83b0132cb195c995bc7688c9fac34bbf2b14e14394b8bbe2991bc017f").unwrap(); - assert_eq!(address, expected); -} - -#[test] -fn test_spend_policy_encode_pubkey() { - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let policy = SpendPolicy::PublicKey(pubkey); - - let hash = policy.encode().hash(); - let expected = H256::from("4355c8f80f6e5a98b70c9c2f9a22f17747989b4744783c90439b2b034f698bfe"); - assert_eq!(hash, expected); - - let address = policy.address(); - let expected = - Address::from_str("addr:55a7793237722c6df8222fd512063cb74228085ef1805c5184713648c159b919ac792fbad0e1").unwrap(); - assert_eq!(address, expected); -} - -#[test] -fn test_spend_policy_encode_hash() { - let hash = H256::from("0102030000000000000000000000000000000000000000000000000000000000"); - let policy = SpendPolicy::Hash(hash); - - let encoded = policy.encode(); - let hash = encoded.hash(); - let expected = H256::from("9938967aefa6cbecc1f1620d2df5170d6811d4b2f47a879b621c1099a3b0628a"); - assert_eq!(hash, expected); - - let address = policy.address(); - let expected = - Address::from_str("addr:a4d5a06d8d3c2e45aa26627858ce8e881505ae3c9d122a1d282c7824163751936cffb347e435").unwrap(); - assert_eq!(address, expected); -} - -#[test] -fn test_spend_policy_encode_threshold() { - let policy = SpendPolicy::Threshold(PolicyTypeThreshold { - n: 1, - of: vec![SpendPolicy::above(1), SpendPolicy::after(1)], - }); - - let encoded = policy.encode(); - let hash = encoded.hash(); - let expected = H256::from("7d792df6cd0b5e0f795287b3bf4087bbcc4c1bd0c52880a552cdda3e5e33d802"); - assert_eq!(hash, expected); - - let address = policy.address(); - let expected = - Address::from_str("addr:4179b53aba165e46e4c85b3c8766bb758fb6f0bfa5721550b81981a3ec38efc460557dc1ded4").unwrap(); - assert_eq!(address, expected); -} - -#[test] -fn test_spend_policy_encode_unlock_condition() { - let pubkey = PublicKey::from_bytes( - &hex::decode("0102030000000000000000000000000000000000000000000000000000000000").unwrap(), - ) - .unwrap(); - let unlock_condition = UnlockCondition::new(vec![pubkey], 0, 1); - - let sub_policy = SpendPolicy::UnlockConditions(PolicyTypeUnlockConditions(unlock_condition)); - let base_address = sub_policy.address(); - let expected = - Address::from_str("addr:72b0762b382d4c251af5ae25b6777d908726d75962e5224f98d7f619bb39515dd64b9a56043a").unwrap(); - assert_eq!(base_address, expected); - - let policy = SpendPolicy::Threshold(PolicyTypeThreshold { - n: 1, - of: vec![sub_policy], - }); - let address = policy.address(); - let expected = - Address::from_str("addr:1498a58c843ce66740e52421632d67a0f6991ea96db1fc97c29e46f89ae56e3534078876331d").unwrap(); - assert_eq!(address, expected); -} diff --git a/mm2src/coins/sia.rs b/mm2src/coins/siacoin.rs similarity index 84% rename from mm2src/coins/sia.rs rename to mm2src/coins/siacoin.rs index 446a507070..4e77a74731 100644 --- a/mm2src/coins/sia.rs +++ b/mm2src/coins/siacoin.rs @@ -1,5 +1,5 @@ -use super::{CoinBalance, HistorySyncState, MarketCoinOps, MmCoin, RawTransactionFut, RawTransactionRequest, SwapOps, - TradeFee, TransactionEnum, TransactionFut}; +use super::{BalanceError, CoinBalance, HistorySyncState, MarketCoinOps, MmCoin, RawTransactionFut, + RawTransactionRequest, SwapOps, TradeFee, TransactionEnum, TransactionFut}; use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinFutSpawner, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, MakerSwapTakerCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, @@ -14,25 +14,22 @@ use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPay WithdrawRequest}; use async_trait::async_trait; use common::executor::AbortedError; +pub use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature}; use futures::{FutureExt, TryFutureExt}; use futures01::Future; use keys::KeyPair; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; -use mm2_number::{BigDecimal, MmNumber}; +use mm2_number::{BigDecimal, BigInt, MmNumber}; use rpc::v1::types::Bytes as BytesJson; use serde_json::Value as Json; use std::ops::Deref; use std::sync::Arc; -use url::Url; -pub mod address; -use address::v1_standard_address_from_pubkey; -pub mod blake2b_internal; -pub mod encoding; -pub mod http_client; -use http_client::{SiaApiClient, SiaApiClientError}; -pub mod spend_policy; +use sia_rust::http_client::{SiaApiClient, SiaApiClientError, SiaHttpConf}; +use sia_rust::spend_policy::SpendPolicy; + +pub mod sia_hd_wallet; #[derive(Clone)] pub struct SiaCoin(SiaArc); @@ -54,12 +51,6 @@ pub struct SiaCoinConf { pub foo: u32, } -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct SiaHttpConf { - pub url: Url, - pub auth: String, -} - // TODO see https://github.com/KomodoPlatform/komodo-defi-framework/pull/2086#discussion_r1521660384 // for additional fields needed #[derive(Clone, Debug, Deserialize, Serialize)] @@ -93,7 +84,7 @@ impl<'a> SiaConfBuilder<'a> { pub struct SiaCoinFields { /// SIA coin config pub conf: SiaCoinConf, - pub priv_key_policy: PrivKeyPolicy, + pub priv_key_policy: PrivKeyPolicy, /// HTTP(s) client pub http_client: SiaApiClient, } @@ -118,7 +109,7 @@ pub struct SiaCoinBuilder<'a> { ctx: &'a MmArc, ticker: &'a str, conf: &'a Json, - key_pair: ed25519_dalek::Keypair, + key_pair: Keypair, params: &'a SiaCoinActivationParams, } @@ -127,7 +118,7 @@ impl<'a> SiaCoinBuilder<'a> { ctx: &'a MmArc, ticker: &'a str, conf: &'a Json, - key_pair: ed25519_dalek::Keypair, + key_pair: Keypair, params: &'a SiaCoinActivationParams, ) -> Self { SiaCoinBuilder { @@ -140,15 +131,22 @@ impl<'a> SiaCoinBuilder<'a> { } } -fn generate_keypair_from_slice(priv_key: &[u8]) -> Result { - let secret_key = ed25519_dalek::SecretKey::from_bytes(priv_key).map_err(SiaCoinBuildError::EllipticCurveError)?; - let public_key = ed25519_dalek::PublicKey::from(&secret_key); - Ok(ed25519_dalek::Keypair { +fn generate_keypair_from_slice(priv_key: &[u8]) -> Result { + let secret_key = SecretKey::from_bytes(priv_key).map_err(SiaCoinBuildError::EllipticCurveError)?; + let public_key = PublicKey::from(&secret_key); + Ok(Keypair { secret: secret_key, public: public_key, }) } +/// Convert hastings amount to siacoin amount +fn siacoin_from_hastings(hastings: u128) -> BigDecimal { + let hastings = BigInt::from(hastings); + let decimals = BigInt::from(10u128.pow(24)); + BigDecimal::from(hastings) / BigDecimal::from(decimals) +} + impl From for SiaCoinBuildError { fn from(e: SiaConfError) -> Self { SiaCoinBuildError::ConfError(e) } } @@ -174,8 +172,9 @@ impl<'a> SiaCoinBuilder<'a> { let conf = SiaConfBuilder::new(self.conf, self.ticker()).build()?; let sia_fields = SiaCoinFields { conf, - http_client: SiaApiClient::new(self.ticker(), self.params.http_conf.clone()) - .map_err(SiaCoinBuildError::ClientError)?, + http_client: SiaApiClient::new(self.params.http_conf.clone()) + .map_err(SiaCoinBuildError::ClientError) + .await?, priv_key_policy: PrivKeyPolicy::Iguana(self.key_pair), }; let sia_arc = SiaArc::new(sia_fields); @@ -306,9 +305,15 @@ impl MarketCoinOps for SiaCoin { ) .into()); }, + #[cfg(target_arch = "wasm32")] + PrivKeyPolicy::Metamask(_) => { + return Err(MyAddressError::UnexpectedDerivationMethod( + "Metamask not supported. Must use iguana seed.".to_string(), + ) + .into()); + }, }; - - let address = v1_standard_address_from_pubkey(&key_pair.public); + let address = SpendPolicy::PublicKey(key_pair.public).address(); Ok(address.to_string()) } @@ -323,14 +328,30 @@ impl MarketCoinOps for SiaCoin { } fn my_balance(&self) -> BalanceFut { + let coin = self.clone(); let fut = async move { + let my_address = match &coin.0.priv_key_policy { + PrivKeyPolicy::Iguana(key_pair) => SpendPolicy::PublicKey(key_pair.public).address(), + _ => { + return MmError::err(BalanceError::UnexpectedDerivationMethod( + UnexpectedDerivationMethod::ExpectedSingleAddress, + )) + }, + }; + let balance = coin + .0 + .http_client + .address_balance(my_address) + .await + .map_to_mm(|e| BalanceError::Transport(e.to_string()))?; Ok(CoinBalance { - spendable: BigDecimal::default(), - unspendable: BigDecimal::default(), + spendable: siacoin_from_hastings(balance.siacoins.to_u128()), + unspendable: siacoin_from_hastings(balance.immature_siacoins.to_u128()), }) }; Box::new(fut.boxed().compat()) } + fn base_coin_balance(&self) -> BalanceFut { unimplemented!() } fn platform_ticker(&self) -> &str { "FOO" } // TODO Alright @@ -360,7 +381,7 @@ impl MarketCoinOps for SiaCoin { fn current_block(&self) -> Box + Send> { let http_client = self.0.http_client.clone(); // Clone the client - let height_fut = async move { http_client.get_height().await.map_err(|e| e.to_string()) } + let height_fut = async move { http_client.current_height().await.map_err(|e| e.to_string()) } .boxed() // Make the future 'static by boxing .compat(); // Convert to a futures 0.1-compatible future @@ -596,3 +617,29 @@ impl WatcherOps for SiaCoin { unimplemented!() } } + +#[cfg(test)] +mod tests { + use super::*; + use mm2_number::BigDecimal; + use std::str::FromStr; + + #[test] + fn test_siacoin_from_hastings() { + let hastings = u128::MAX; + let siacoin = siacoin_from_hastings(hastings); + assert_eq!( + siacoin, + BigDecimal::from_str("340282366920938.463463374607431768211455").unwrap() + ); + + let hastings = 0; + let siacoin = siacoin_from_hastings(hastings); + assert_eq!(siacoin, BigDecimal::from_str("0").unwrap()); + + // Total supply of Siacoin + let hastings = 57769875000000000000000000000000000; + let siacoin = siacoin_from_hastings(hastings); + assert_eq!(siacoin, BigDecimal::from_str("57769875000").unwrap()); + } +} diff --git a/mm2src/coins/siacoin/sia_hd_wallet.rs b/mm2src/coins/siacoin/sia_hd_wallet.rs new file mode 100644 index 0000000000..4c6a288ef5 --- /dev/null +++ b/mm2src/coins/siacoin/sia_hd_wallet.rs @@ -0,0 +1,44 @@ +use crate::hd_wallet::{HDAccount, HDAddress, HDWallet}; +use bip32::{ExtendedPublicKey, PrivateKeyBytes, PublicKey as bip32PublicKey, PublicKeyBytes, Result as bip32Result}; +use sia_rust::types::Address; +use sia_rust::PublicKey; + +pub struct SiaPublicKey(pub PublicKey); + +pub type SiaHDAddress = HDAddress; +pub type SiaHDAccount = HDAccount; +pub type SiaHDWallet = HDWallet; +pub type Ed25519ExtendedPublicKey = ExtendedPublicKey; + +impl bip32PublicKey for SiaPublicKey { + fn from_bytes(_bytes: PublicKeyBytes) -> bip32Result { + todo!() + //Ok(secp256k1_ffi::PublicKey::from_slice(&bytes)?) + } + + fn to_bytes(&self) -> PublicKeyBytes { + todo!() + // self.serialize() + } + + fn derive_child(&self, _other: PrivateKeyBytes) -> bip32Result { + todo!() + // use secp256k1_ffi::{Secp256k1, VerifyOnly}; + // let engine = Secp256k1::::verification_only(); + + // let mut child_key = *self; + // child_key + // .add_exp_assign(&engine, &other) + // .map_err(|_| Error::Crypto)?; + + // Ok(child_key) + } +} + +// coin type 1991 +// path component 0x800007c7 + +#[test] +fn test_something() { + println!("This is a test"); +} diff --git a/mm2src/coins_activation/src/prelude.rs b/mm2src/coins_activation/src/prelude.rs index 236d19b1c1..d000170fa3 100644 --- a/mm2src/coins_activation/src/prelude.rs +++ b/mm2src/coins_activation/src/prelude.rs @@ -1,5 +1,5 @@ #[cfg(feature = "enable-sia")] -use coins::sia::SiaCoinActivationParams; +use coins::siacoin::SiaCoinActivationParams; use coins::utxo::UtxoActivationParams; use coins::z_coin::ZcoinActivationParams; use coins::{coin_conf, CoinBalance, CoinProtocol, DerivationMethodResponse, MmCoinEnum}; diff --git a/mm2src/coins_activation/src/sia_coin_activation.rs b/mm2src/coins_activation/src/sia_coin_activation.rs index 7dd7539f66..11c72955ab 100644 --- a/mm2src/coins_activation/src/sia_coin_activation.rs +++ b/mm2src/coins_activation/src/sia_coin_activation.rs @@ -7,8 +7,8 @@ use async_trait::async_trait; use coins::coin_balance::{CoinBalanceReport, IguanaWalletBalance}; use coins::coin_errors::MyAddressError; use coins::my_tx_history_v2::TxHistoryStorage; -use coins::sia::{sia_coin_from_conf_and_params, SiaCoin, SiaCoinActivationParams, SiaCoinBuildError, - SiaCoinProtocolInfo}; +use coins::siacoin::{sia_coin_from_conf_and_params, SiaCoin, SiaCoinActivationParams, SiaCoinBuildError, + SiaCoinProtocolInfo}; use coins::tx_history_storage::CreateTxHistoryStorageError; use coins::{BalanceError, CoinBalance, CoinProtocol, MarketCoinOps, PrivKeyBuildPolicy, RegisterCoinError}; use crypto::hw_rpc_task::{HwRpcTaskAwaitingStatus, HwRpcTaskUserAction}; diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index f3232ac91e..60c3e9aa62 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -19,11 +19,11 @@ track-ctx-pointer = ["common/track-ctx-pointer"] zhtlc-native-tests = ["coins/zhtlc-native-tests"] run-docker-tests = ["coins/run-docker-tests"] # TODO -enable-solana = [] +enable-solana = ["coins/enable-solana", "coins_activation/enable-solana"] default = [] trezor-udp = ["crypto/trezor-udp"] # use for tests to connect to trezor emulator over udp run-device-tests = [] -enable-sia = [] +enable-sia = ["coins/enable-sia", "coins_activation/enable-sia"] [dependencies] async-std = { version = "1.5", features = ["unstable"] } @@ -132,6 +132,8 @@ ethabi = { version = "17.0.0" } rlp = { version = "0.5" } ethcore-transaction = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git", rev = "mm2-v2.1.1" } rustc-hex = "2" +sia-rust = { git = "https://github.com/KomodoPlatform/sia-rust", rev = "9f188b80b3213bcb604e7619275251ce08fae808" } +url = { version = "2.2.2", features = ["serde"] } [build-dependencies] chrono = "0.4" diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index 5403392240..b9066bf540 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -28,7 +28,7 @@ use coins::rpc_command::{account_balance::account_balance, init_scan_for_new_addresses::{cancel_scan_for_new_addresses, init_scan_for_new_addresses, init_scan_for_new_addresses_status}, init_withdraw::{cancel_withdraw, init_withdraw, withdraw_status, withdraw_user_action}}; -#[cfg(feature = "enable-sia")] use coins::sia::SiaCoin; +#[cfg(feature = "enable-sia")] use coins::siacoin::SiaCoin; use coins::tendermint::{TendermintCoin, TendermintToken}; use coins::utxo::bch::BchCoin; use coins::utxo::qtum::QtumCoin; diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index 4e294e6031..fe5d7f96d4 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -105,6 +105,10 @@ pub const UTXO_ASSET_DOCKER_IMAGE: &str = "docker.io/artempikulin/testblockchain pub const UTXO_ASSET_DOCKER_IMAGE_WITH_TAG: &str = "docker.io/artempikulin/testblockchain:multiarch"; pub const GETH_DOCKER_IMAGE: &str = "docker.io/ethereum/client-go"; pub const GETH_DOCKER_IMAGE_WITH_TAG: &str = "docker.io/ethereum/client-go:stable"; +#[allow(dead_code)] +pub const SIA_DOCKER_IMAGE: &str = "docker.io/alrighttt/walletd-komodo"; +#[allow(dead_code)] +pub const SIA_DOCKER_IMAGE_WITH_TAG: &str = "docker.io/alrighttt/walletd-komodo:latest"; pub const NUCLEUS_IMAGE: &str = "docker.io/komodoofficial/nucleusd"; pub const ATOM_IMAGE: &str = "docker.io/komodoofficial/gaiad"; @@ -371,6 +375,22 @@ pub fn geth_docker_node<'a>(docker: &'a Cli, ticker: &'static str, port: u16) -> } } +#[allow(dead_code)] +pub fn sia_docker_node<'a>(docker: &'a Cli, ticker: &'static str, port: u16) -> DockerNode<'a> { + let image = + GenericImage::new(SIA_DOCKER_IMAGE, "latest").with_env_var("WALLETD_API_PASSWORD", "password".to_string()); + let args = vec![]; + let image = RunnableImage::from((image, args)) + .with_mapped_port((port, port)) + .with_container_name("sia-docker"); + let container = docker.run(image); + DockerNode { + container, + ticker: ticker.into(), + port, + } +} + pub fn nucleus_node(docker: &'_ Cli, runtime_dir: PathBuf) -> DockerNode<'_> { let nucleus_node_runtime_dir = runtime_dir.join("nucleus-testnet-data"); assert!(nucleus_node_runtime_dir.exists()); diff --git a/mm2src/mm2_main/tests/docker_tests/mod.rs b/mm2src/mm2_main/tests/docker_tests/mod.rs index 2adfe3b2c9..685f1bcad8 100644 --- a/mm2src/mm2_main/tests/docker_tests/mod.rs +++ b/mm2src/mm2_main/tests/docker_tests/mod.rs @@ -4,6 +4,7 @@ mod docker_ordermatch_tests; mod docker_tests_inner; mod eth_docker_tests; pub mod qrc20_tests; +#[cfg(feature = "enable-sia")] mod sia_docker_tests; mod slp_tests; #[cfg(feature = "enable-solana")] mod solana_tests; mod swap_proto_v2_tests; diff --git a/mm2src/mm2_main/tests/docker_tests/sia_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/sia_docker_tests.rs new file mode 100644 index 0000000000..b8546aa218 --- /dev/null +++ b/mm2src/mm2_main/tests/docker_tests/sia_docker_tests.rs @@ -0,0 +1,118 @@ +use common::block_on; +use sia_rust::http_client::{SiaApiClient, SiaApiClientError, SiaHttpConf}; +use sia_rust::http_endpoints::{AddressBalanceRequest, AddressUtxosRequest, ConsensusTipRequest, TxpoolBroadcastRequest}; +use sia_rust::spend_policy::SpendPolicy; +use sia_rust::transaction::{SiacoinOutput, V2TransactionBuilder}; +use sia_rust::types::{Address, Currency}; +use sia_rust::{Keypair, PublicKey, SecretKey}; +use std::process::Command; +use std::str::FromStr; +use url::Url; + +#[cfg(test)] +fn mine_blocks(n: u64, addr: &Address) { + Command::new("docker") + .arg("exec") + .arg("sia-docker") + .arg("walletd") + .arg("mine") + .arg(format!("-addr={}", addr)) + .arg(format!("-n={}", n)) + .status() + .expect("Failed to execute docker command"); +} + +#[test] +fn test_sia_new_client() { + let conf = SiaHttpConf { + url: Url::parse("http://localhost:9980/").unwrap(), + password: "password".to_string(), + }; + let _api_client = block_on(SiaApiClient::new(conf)).unwrap(); +} + +#[test] +fn test_sia_client_bad_auth() { + let conf = SiaHttpConf { + url: Url::parse("http://localhost:9980/").unwrap(), + password: "foo".to_string(), + }; + let result = block_on(SiaApiClient::new(conf)); + assert!(matches!(result, Err(SiaApiClientError::UnexpectedHttpStatus(401)))); +} + +#[test] +fn test_sia_client_consensus_tip() { + let conf = SiaHttpConf { + url: Url::parse("http://localhost:9980/").unwrap(), + password: "password".to_string(), + }; + let api_client = block_on(SiaApiClient::new(conf)).unwrap(); + let _response = block_on(api_client.dispatcher(ConsensusTipRequest)).unwrap(); +} + +// This test likely needs to be removed because mine_blocks has possibility of interfering with other async tests +// related to block height +#[test] +fn test_sia_client_address_balance() { + let conf = SiaHttpConf { + url: Url::parse("http://localhost:9980/").unwrap(), + password: "password".to_string(), + }; + let api_client = block_on(SiaApiClient::new(conf)).unwrap(); + + let address = + Address::from_str("addr:591fcf237f8854b5653d1ac84ae4c107b37f148c3c7b413f292d48db0c25a8840be0653e411f").unwrap(); + mine_blocks(10, &address); + + let request = AddressBalanceRequest { address }; + let response = block_on(api_client.dispatcher(request)).unwrap(); + + let expected = Currency::new(12919594847110692864, 54210108624275221); + assert_eq!(response.siacoins, expected); + assert_eq!(expected.to_u128(), 1000000000000000000000000000000000000); +} + +#[test] +fn test_sia_client_build_tx() { + let conf = SiaHttpConf { + url: Url::parse("http://localhost:9980/").unwrap(), + password: "password".to_string(), + }; + let api_client = block_on(SiaApiClient::new(conf)).unwrap(); + let sk: SecretKey = SecretKey::from_bytes( + &hex::decode("0100000000000000000000000000000000000000000000000000000000000000").unwrap(), + ) + .unwrap(); + let pk: PublicKey = (&sk).into(); + let keypair = Keypair { public: pk, secret: sk }; + let spend_policy = SpendPolicy::PublicKey(pk); + + let address = spend_policy.address(); + + mine_blocks(201, &address); + + let utxos = block_on(api_client.dispatcher(AddressUtxosRequest { + address: address.clone(), + })) + .unwrap(); + let spend_this = utxos[0].clone(); + let vin = spend_this.clone(); + println!("utxo[0]: {:?}", spend_this); + let vout = SiacoinOutput { + value: spend_this.siacoin_output.value, + address, + }; + let tx = V2TransactionBuilder::new(0u64.into()) + .add_siacoin_input(vin, spend_policy) + .add_siacoin_output(vout) + .sign_simple(vec![&keypair]) + .unwrap() + .build(); + + let req = TxpoolBroadcastRequest { + transactions: vec![], + v2transactions: vec![tx], + }; + let _response = block_on(api_client.dispatcher(req)).unwrap(); +} diff --git a/mm2src/mm2_main/tests/docker_tests_main.rs b/mm2src/mm2_main/tests/docker_tests_main.rs index 5225f1b029..5f0045ea33 100644 --- a/mm2src/mm2_main/tests/docker_tests_main.rs +++ b/mm2src/mm2_main/tests/docker_tests_main.rs @@ -173,6 +173,7 @@ fn remove_docker_containers(name: &str) { .expect("Failed to execute docker command"); } } + fn prepare_runtime_dir() -> std::io::Result { let project_root = { let mut current_dir = std::env::current_dir().unwrap(); diff --git a/mm2src/mm2_main/tests/docker_tests_sia_unique.rs b/mm2src/mm2_main/tests/docker_tests_sia_unique.rs new file mode 100644 index 0000000000..521da60e01 --- /dev/null +++ b/mm2src/mm2_main/tests/docker_tests_sia_unique.rs @@ -0,0 +1,106 @@ +#![allow(unused_imports, dead_code)] +#![cfg(feature = "enable-sia")] +#![feature(async_closure)] +#![feature(custom_test_frameworks)] +#![feature(test)] +#![test_runner(docker_tests_runner)] +#![feature(drain_filter)] +#![feature(hash_raw_entry)] +#![cfg(not(target_arch = "wasm32"))] + +#[cfg(test)] +#[macro_use] +extern crate common; +#[cfg(test)] +#[macro_use] +extern crate gstuff; +#[cfg(test)] +#[macro_use] +extern crate lazy_static; +#[cfg(test)] +#[macro_use] +extern crate serde_json; +#[cfg(test)] extern crate ser_error_derive; +#[cfg(test)] extern crate test; + +use std::env; +use std::io::{BufRead, BufReader}; +use std::path::PathBuf; +use std::process::Command; +use test::{test_main, StaticBenchFn, StaticTestFn, TestDescAndFn}; +use testcontainers::clients::Cli; + +mod docker_tests; +use docker_tests::docker_tests_common::*; + +#[allow(dead_code)] mod integration_tests_common; + +/// Custom test runner intended to initialize the SIA coin daemon in a Docker container. +pub fn docker_tests_runner(tests: &[&TestDescAndFn]) { + let docker = Cli::default(); + let mut containers = vec![]; + + let skip_docker_tests_runner = std::env::var("SKIP_DOCKER_TESTS_RUNNER") + .map(|v| v == "1") + .unwrap_or(false); + + if !skip_docker_tests_runner { + const IMAGES: &[&str] = &[SIA_DOCKER_IMAGE_WITH_TAG]; + + for image in IMAGES { + pull_docker_image(image); + remove_docker_containers(image); + } + + let sia_node = sia_docker_node(&docker, "SIA", 9980); + println!("ran container?"); + containers.push(sia_node); + } + // detect if docker is installed + // skip the tests that use docker if not installed + let owned_tests: Vec<_> = tests + .iter() + .map(|t| match t.testfn { + StaticTestFn(f) => TestDescAndFn { + testfn: StaticTestFn(f), + desc: t.desc.clone(), + }, + StaticBenchFn(f) => TestDescAndFn { + testfn: StaticBenchFn(f), + desc: t.desc.clone(), + }, + _ => panic!("non-static tests passed to lp_coins test runner"), + }) + .collect(); + let args: Vec = env::args().collect(); + test_main(&args, owned_tests, None); +} + +fn pull_docker_image(name: &str) { + Command::new("docker") + .arg("pull") + .arg(name) + .status() + .expect("Failed to execute docker command"); +} + +fn remove_docker_containers(name: &str) { + let stdout = Command::new("docker") + .arg("ps") + .arg("-f") + .arg(format!("ancestor={}", name)) + .arg("-q") + .output() + .expect("Failed to execute docker command"); + + let reader = BufReader::new(stdout.stdout.as_slice()); + let ids: Vec<_> = reader.lines().map(|line| line.unwrap()).collect(); + if !ids.is_empty() { + Command::new("docker") + .arg("rm") + .arg("-f") + .args(ids) + .status() + .expect("Failed to execute docker command"); + } +} From 7ca140a18957034be9b28adc53deda38760ee07d Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Fri, 30 Aug 2024 12:20:45 +0100 Subject: [PATCH 05/15] chore(test): turn on debug assertion (#2204) This commit removes zcoin additional chain validation to turn on debug assertion. --- Cargo.toml | 6 +----- mm2src/coins/z_coin/storage.rs | 23 ++--------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 758587e557..deec6b843f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,10 +61,6 @@ codegen-units = 1 # lto = true panic = "abort" -[profile.test] -# required to avoid a long running process of librustcash additional chain validation that is enabled with debug assertions -debug-assertions = false - [profile.dev] opt-level = 0 debug = 1 @@ -74,4 +70,4 @@ incremental = true codegen-units = 256 [profile.release.package.mocktopus] -opt-level = 1 # TODO: MIR fails on optimizing this dependency, remove that.. \ No newline at end of file +opt-level = 1 # TODO: MIR fails on optimizing this dependency, remove that.. diff --git a/mm2src/coins/z_coin/storage.rs b/mm2src/coins/z_coin/storage.rs index 08e478f27a..b3c2c108c4 100644 --- a/mm2src/coins/z_coin/storage.rs +++ b/mm2src/coins/z_coin/storage.rs @@ -157,27 +157,8 @@ pub async fn scan_cached_block( ) }; - // Enforce that all roots match. This is slow, so only include in debug builds. - #[cfg(debug_assertions)] - { - let cur_root = tree.root(); - if witnesses.iter().any(|row| row.1.root() != cur_root) { - return Err(Error::InvalidWitnessAnchor(row.0, current_height).into()); - } - for tx in &txs { - for output in tx.shielded_outputs.iter() { - if output.witness.root() != cur_root { - return Err(Error::InvalidNewWitnessAnchor( - output.index, - tx.txid, - current_height, - output.witness.root(), - ) - .into()); - } - } - } - } + // To enforce that all roots match, + // see -> https://github.com/KomodoPlatform/librustzcash/blob/e92443a7bbd1c5e92e00e6deb45b5a33af14cea4/zcash_client_backend/src/data_api/chain.rs#L304-L326 let new_witnesses = data_guard .advance_by_block( From ffed8606ae5e74076b295018c4fec04ab2da42db Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 5 Sep 2024 03:18:59 +0300 Subject: [PATCH 06/15] fix(coins): add p2p feature to mm2_net dependency (#2210) This makes coins a separate crate that can be tested and checked separately. --- mm2src/coins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index c5eeb570ea..c870e9baf0 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -78,7 +78,7 @@ mm2_event_stream = { path = "../mm2_event_stream" } mm2_git = { path = "../mm2_git" } mm2_io = { path = "../mm2_io" } mm2_metrics = { path = "../mm2_metrics" } -mm2_net = { path = "../mm2_net" } +mm2_net = { path = "../mm2_net", features = ["p2p"] } mm2_number = { path = "../mm2_number"} mm2_rpc = { path = "../mm2_rpc" } mm2_state_machine = { path = "../mm2_state_machine" } From c3666303c3401efe533aa06c9f1d38834e3f6026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Fri, 6 Sep 2024 23:50:04 +0300 Subject: [PATCH 07/15] chore(WASM-builds): remove `wasm-opt` overriding (#2200) --- mm2src/mm2_bin_lib/Cargo.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mm2src/mm2_bin_lib/Cargo.toml b/mm2src/mm2_bin_lib/Cargo.toml index 94e4e6d88e..7415f21b4f 100644 --- a/mm2src/mm2_bin_lib/Cargo.toml +++ b/mm2src/mm2_bin_lib/Cargo.toml @@ -10,11 +10,6 @@ authors = ["James Lee", "Artem Pikulin", "Artem Grinblat", "Omar S.", "Onur Ozka edition = "2018" default-run = "kdf" -# wasm-opt reduces the size from 17 Mb to 14. But it runs for few minutes, which is not good for CI. -# For production builds, it's recommended to run wasm-opt separately. -[package.metadata.wasm-pack.profile.release] -wasm-opt = false - [features] custom-swap-locktime = ["mm2_main/custom-swap-locktime"] # only for testing purposes, should never be activated on release builds. native = ["mm2_main/native"] # Deprecated From d1a8ea7a17d6199c1a2460ab8a3d360a968ea36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Tue, 10 Sep 2024 09:26:03 +0300 Subject: [PATCH 08/15] chore(RPCs): rename `get_peers_info` RPC to `get_directly_connected_peers` (#2195) `get_peers_info` RPC had a misleading name, it only returns the directly connected peers, not all network peers. This commit renames the RPC to `get_directly_connected_peers` which causes a breaking change. --- mm2src/mm2_libp2p/src/atomicdex_behaviour.rs | 4 ++-- mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs | 2 +- .../mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs | 4 ++-- mm2src/mm2_net/src/network_event.rs | 4 ++-- mm2src/mm2_p2p/src/behaviours/atomicdex.rs | 4 ++-- mm2src/mm2_p2p/src/lib.rs | 9 +++++---- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/mm2src/mm2_libp2p/src/atomicdex_behaviour.rs b/mm2src/mm2_libp2p/src/atomicdex_behaviour.rs index 482251fb93..c0f2c47725 100644 --- a/mm2src/mm2_libp2p/src/atomicdex_behaviour.rs +++ b/mm2src/mm2_libp2p/src/atomicdex_behaviour.rs @@ -46,8 +46,8 @@ const ANNOUNCE_INTERVAL: Duration = Duration::from_secs(600); const ANNOUNCE_INITIAL_DELAY: Duration = Duration::from_secs(60); const CHANNEL_BUF_SIZE: usize = 1024 * 8; -/// Returns info about connected peers -pub async fn get_peers_info(mut cmd_tx: AdexCmdTx) -> BTreeMap> { +/// Returns info about directly connected peers. +pub async fn get_directly_connected_peers(mut cmd_tx: AdexCmdTx) -> BTreeMap> { let (result_tx, rx) = oneshot::channel(); let cmd = AdexBehaviourCmd::GetPeersInfo { result_tx }; cmd_tx.send(cmd).await.expect("Rx should be present"); diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs index bcb09c4d51..2415bc31ef 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs @@ -73,11 +73,11 @@ pub fn dispatcher(req: Json, ctx: MmArc) -> DispatcherRes { "electrum" => hyres(electrum(ctx, req)), "enable" => hyres(enable(ctx, req)), "get_enabled_coins" => hyres(get_enabled_coins(ctx)), + "get_directly_connected_peers" => hyres(get_directly_connected_peers(ctx)), "get_gossip_mesh" => hyres(get_gossip_mesh(ctx)), "get_gossip_peer_topics" => hyres(get_gossip_peer_topics(ctx)), "get_gossip_topic_peers" => hyres(get_gossip_topic_peers(ctx)), "get_my_peer_id" => hyres(get_my_peer_id(ctx)), - "get_peers_info" => hyres(get_peers_info(ctx)), "get_relay_mesh" => hyres(get_relay_mesh(ctx)), "get_trade_fee" => hyres(get_trade_fee(ctx, req)), // "fundvalue" => lp_fundvalue (ctx, req, false), diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs index 2769539d9b..7db7c5b02b 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs @@ -316,10 +316,10 @@ pub fn version(ctx: MmArc) -> HyRes { } } -pub async fn get_peers_info(ctx: MmArc) -> Result>, String> { +pub async fn get_directly_connected_peers(ctx: MmArc) -> Result>, String> { let ctx = P2PContext::fetch_from_mm_arc(&ctx); let cmd_tx = ctx.cmd_tx.lock().clone(); - let result = mm2_libp2p::get_peers_info(cmd_tx).await; + let result = mm2_libp2p::get_directly_connected_peers(cmd_tx).await; let result = json!({ "result": result, }); diff --git a/mm2src/mm2_net/src/network_event.rs b/mm2src/mm2_net/src/network_event.rs index b88655f383..9ff7ae15f7 100644 --- a/mm2src/mm2_net/src/network_event.rs +++ b/mm2src/mm2_net/src/network_event.rs @@ -30,14 +30,14 @@ impl EventBehaviour for NetworkEvent { loop { let p2p_cmd_tx = p2p_ctx.cmd_tx.lock().clone(); - let peers_info = atomicdex::get_peers_info(p2p_cmd_tx.clone()).await; + let directly_connected_peers = atomicdex::get_directly_connected_peers(p2p_cmd_tx.clone()).await; let gossip_mesh = atomicdex::get_gossip_mesh(p2p_cmd_tx.clone()).await; let gossip_peer_topics = atomicdex::get_gossip_peer_topics(p2p_cmd_tx.clone()).await; let gossip_topic_peers = atomicdex::get_gossip_topic_peers(p2p_cmd_tx.clone()).await; let relay_mesh = atomicdex::get_relay_mesh(p2p_cmd_tx).await; let event_data = json!({ - "peers_info": peers_info, + "directly_connected_peers": directly_connected_peers, "gossip_mesh": gossip_mesh, "gossip_peer_topics": gossip_peer_topics, "gossip_topic_peers": gossip_topic_peers, diff --git a/mm2src/mm2_p2p/src/behaviours/atomicdex.rs b/mm2src/mm2_p2p/src/behaviours/atomicdex.rs index db907711ba..9d58da4e1e 100644 --- a/mm2src/mm2_p2p/src/behaviours/atomicdex.rs +++ b/mm2src/mm2_p2p/src/behaviours/atomicdex.rs @@ -162,8 +162,8 @@ pub enum AdexBehaviourCmd { }, } -/// Returns info about connected peers -pub async fn get_peers_info(mut cmd_tx: AdexCmdTx) -> HashMap> { +/// Returns info about directly connected peers. +pub async fn get_directly_connected_peers(mut cmd_tx: AdexCmdTx) -> HashMap> { let (result_tx, rx) = oneshot::channel(); let cmd = AdexBehaviourCmd::GetPeersInfo { result_tx }; cmd_tx.send(cmd).await.expect("Rx should be present"); diff --git a/mm2src/mm2_p2p/src/lib.rs b/mm2src/mm2_p2p/src/lib.rs index e9a8f78ad4..8e6e6db159 100644 --- a/mm2src/mm2_p2p/src/lib.rs +++ b/mm2src/mm2_p2p/src/lib.rs @@ -16,10 +16,11 @@ use sha2::{Digest, Sha256}; pub use crate::swarm_runtime::SwarmRuntime; // atomicdex related re-exports -pub use behaviours::atomicdex::{get_gossip_mesh, get_gossip_peer_topics, get_gossip_topic_peers, get_peers_info, - get_relay_mesh, spawn_gossipsub, AdexBehaviourCmd, AdexBehaviourError, - AdexBehaviourEvent, AdexCmdTx, AdexEventRx, AdexResponse, AdexResponseChannel, - GossipsubEvent, GossipsubMessage, MessageId, NodeType, TopicHash, WssCerts}; +pub use behaviours::atomicdex::{get_directly_connected_peers, get_gossip_mesh, get_gossip_peer_topics, + get_gossip_topic_peers, get_relay_mesh, spawn_gossipsub, AdexBehaviourCmd, + AdexBehaviourError, AdexBehaviourEvent, AdexCmdTx, AdexEventRx, AdexResponse, + AdexResponseChannel, GossipsubEvent, GossipsubMessage, MessageId, NodeType, TopicHash, + WssCerts}; // peers-exchange re-exports pub use behaviours::peers_exchange::PeerAddresses; From 079ea5e4fd9929a73a6f3a7f62240933d7537a43 Mon Sep 17 00:00:00 2001 From: shamardy <39480341+shamardy@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:11:15 +0300 Subject: [PATCH 09/15] fix(db): stop creating the all-zeroes dir on KDF start (#2218) KDF was creating the default all zeroes db dir on start which is not used, this commit fixes this. --- mm2src/mm2_core/src/mm_ctx.rs | 7 +++++-- mm2src/mm2_main/src/lp_native_dex.rs | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index e891f0b649..ec7ceb036a 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -287,10 +287,13 @@ impl MmCtx { }) } + /// Returns the path to the MM databases root. + #[cfg(not(target_arch = "wasm32"))] + pub fn db_root(&self) -> PathBuf { path_to_db_root(self.conf["dbdir"].as_str()) } + #[cfg(not(target_arch = "wasm32"))] pub fn wallet_file_path(&self, wallet_name: &str) -> PathBuf { - let db_root = path_to_db_root(self.conf["dbdir"].as_str()); - db_root.join(wallet_name.to_string() + ".dat") + self.db_root().join(wallet_name.to_string() + ".dat") } /// MM database path. diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 3b73947ffb..bd875511b0 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -498,9 +498,11 @@ pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { pub async fn lp_init(ctx: MmArc, version: String, datetime: String) -> MmInitResult<()> { info!("Version: {} DT {}", version, datetime); + // Ensure the database root directory exists before initializing the wallet passphrase. + // This is necessary to store the encrypted wallet passphrase if needed. #[cfg(not(target_arch = "wasm32"))] { - let dbdir = ctx.dbdir(); + let dbdir = ctx.db_root(); fs::create_dir_all(&dbdir).map_to_mm(|e| MmInitError::ErrorCreatingDbDir { path: dbdir.clone(), error: e.to_string(), From d6bee9ddd9b9d08db24a827c54699c5dec0f1b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Wed, 18 Sep 2024 12:57:35 +0300 Subject: [PATCH 10/15] remove the non-sense arguments (#2216) Signed-off-by: onur-ozkan --- mm2src/common/common.rs | 13 ------------- mm2src/mm2_main/src/mm2.rs | 11 ----------- 2 files changed, 24 deletions(-) diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index c98fe610d2..0eeb726ad4 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -518,19 +518,6 @@ pub fn set_panic_hook() { })) } -/// Simulates the panic-in-panic crash. -pub fn double_panic_crash() { - struct Panicker; - impl Drop for Panicker { - fn drop(&mut self) { panic!("panic in drop") } - } - let panicker = Panicker; - if 1 < 2 { - panic!("first panic") - } - drop(panicker) // Delays the drop. -} - /// RPC response, returned by the RPC handlers. /// NB: By default the future is executed on the shared asynchronous reactor (`CORE`), /// the handler is responsible for spawning the future on another reactor if it doesn't fit the `CORE` well. diff --git a/mm2src/mm2_main/src/mm2.rs b/mm2src/mm2_main/src/mm2.rs index 7dcc5572cb..4ecfb5706d 100644 --- a/mm2src/mm2_main/src/mm2.rs +++ b/mm2src/mm2_main/src/mm2.rs @@ -42,7 +42,6 @@ #[cfg(not(target_arch = "wasm32"))] use common::block_on; use common::crash_reports::init_crash_reports; -use common::double_panic_crash; use common::log::LogLevel; use common::password_policy::password_policy; use mm2_core::mm_ctx::MmCtxBuilder; @@ -248,16 +247,6 @@ pub fn mm2_main(version: String, datetime: String) { // we're not checking them for the mode switches in order not to risk [untrusted] data being mistaken for a mode switch. let first_arg = args_os.get(1).and_then(|arg| arg.to_str()); - if first_arg == Some("panic") { - panic!("panic message") - } - if first_arg == Some("crash") { - double_panic_crash() - } - if first_arg == Some("stderr") { - eprintln!("This goes to stderr"); - return; - } if first_arg == Some("update_config") { match on_update_config(&args_os) { Ok(_) => println!("Success"), From 3b271721ac7db39f5c99e8ac660f8cea4bfb1eea Mon Sep 17 00:00:00 2001 From: shamardy <39480341+shamardy@users.noreply.github.com> Date: Thu, 19 Sep 2024 03:40:16 +0300 Subject: [PATCH 11/15] docs(README): fix typos (#2212) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0d91d3cded..bec7bd1166 100755 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ ## What is the Komodo DeFi Framework? -The Komodo DeFi Framework is open-source [atomic-swap](https://komodoplatform.com/en/academy/atomic-swaps/) software for seamless, decentralised, peer to peer trading between almost every blockchain asset in existence. This software works with propagation of orderbooks and swap states through the [libp2p](https://libp2p.io/) protocol and uses [Hash Time Lock Contracts (HTLCs)](https://en.bitcoinwiki.org/wiki/Hashed_Timelock_Contracts) for ensuring that the two parties in a swap either mutually complete a trade, or funds return to thier original owner. +The Komodo DeFi Framework is open-source [atomic-swap](https://komodoplatform.com/en/academy/atomic-swaps/) software for seamless, decentralized, peer to peer trading between almost every blockchain asset in existence. This software works with propagation of orderbooks and swap states through the [libp2p](https://libp2p.io/) protocol and uses [Hash Time Lock Contracts (HTLCs)](https://en.bitcoinwiki.org/wiki/Hashed_Timelock_Contracts) for ensuring that the two parties in a swap either mutually complete a trade, or funds return to thier original owner. There is no 3rd party intermediary, no proxy tokens, and at all times users remain in sole possession of their private keys. @@ -172,7 +172,7 @@ Refer to the [Komodo Developer Docs](https://developers.komodoplatform.com/basic ## Project structure -[mm2src](mm2src) - Rust code, contains some parts ported from C `as is` (e.g. `lp_ordermatch`) to reach the most essential/error prone code. Some other modules/crates are reimplemented from scratch. +[mm2src](mm2src) - Rust code, contains some parts ported from C `as is` (e.g. `lp_ordermatch`) to reach the most essential/error-prone code. Some other modules/crates are reimplemented from scratch. ## Additional docs for developers @@ -185,8 +185,8 @@ Refer to the [Komodo Developer Docs](https://developers.komodoplatform.com/basic ## Disclaimer -This repository contains the `work in progress` code of the brand new Komodo DeFi Framework (kdf) built mainly on Rust. -The current state can be considered as a alpha version. +This repository contains the `work in progress` code of the brand-new Komodo DeFi Framework (kdf) built mainly on Rust. +The current state can be considered as an alpha version. **WARNING: Use with test coins only or with assets which value does not exceed an amount you are willing to lose. This is alpha stage software! ** From baa72a74fef4b0e22f766186a04a6252ed785b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 19 Sep 2024 04:35:10 +0300 Subject: [PATCH 12/15] feat(core): handling CTRL-C signal with graceful shutdown (#2213) --- Cargo.toml | 2 +- mm2src/mm2_bin_lib/src/lib.rs | 2 +- mm2src/mm2_core/src/mm_ctx.rs | 15 ++++++++++- mm2src/mm2_main/Cargo.toml | 2 +- mm2src/mm2_main/src/mm2.rs | 27 +++++++++++++++++-- .../src/rpc/lp_commands/lp_commands_legacy.rs | 19 +------------ 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index deec6b843f..f6f7f67e61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ opt-level = 3 strip = true codegen-units = 1 # lto = true -panic = "abort" +panic = 'unwind' [profile.dev] opt-level = 0 diff --git a/mm2src/mm2_bin_lib/src/lib.rs b/mm2src/mm2_bin_lib/src/lib.rs index 81c532419f..c78233e64a 100644 --- a/mm2src/mm2_bin_lib/src/lib.rs +++ b/mm2src/mm2_bin_lib/src/lib.rs @@ -99,5 +99,5 @@ fn prepare_for_mm2_stop() -> PrepareForStopResult { async fn finalize_mm2_stop(ctx: MmArc) { dispatch_lp_event(ctx.clone(), StopCtxEvent.into()).await; - let _ = ctx.stop(); + let _ = ctx.stop().await; } diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index ec7ceb036a..0be8e66734 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -503,7 +503,10 @@ lazy_static! { impl MmArc { pub fn new(ctx: MmCtx) -> MmArc { MmArc(SharedRc::new(ctx)) } - pub fn stop(&self) -> Result<(), String> { + pub async fn stop(&self) -> Result<(), String> { + #[cfg(not(target_arch = "wasm32"))] + try_s!(self.close_async_connection().await); + try_s!(self.stop.pin(true)); // Notify shutdown listeners. @@ -517,6 +520,16 @@ impl MmArc { Ok(()) } + #[cfg(not(target_arch = "wasm32"))] + async fn close_async_connection(&self) -> Result<(), db_common::async_sql_conn::AsyncConnError> { + if let Some(async_conn) = self.async_sqlite_connection.as_option() { + let mut conn = async_conn.lock().await; + conn.close().await?; + } + + Ok(()) + } + #[cfg(feature = "track-ctx-pointer")] fn track_ctx_pointer(&self) { let ctx_weak = self.weak(); diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index 60c3e9aa62..3013bce994 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -116,7 +116,7 @@ hyper = { version = "0.14.26", features = ["client", "http2", "server", "tcp"] } rcgen = "0.10" rustls = { version = "0.21", default-features = false } rustls-pemfile = "1.0.2" -tokio = { version = "1.20", features = ["io-util", "rt-multi-thread", "net"] } +tokio = { version = "1.20", features = ["io-util", "rt-multi-thread", "net", "signal"] } [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/mm2src/mm2_main/src/mm2.rs b/mm2src/mm2_main/src/mm2.rs index 4ecfb5706d..734e71becf 100644 --- a/mm2src/mm2_main/src/mm2.rs +++ b/mm2src/mm2_main/src/mm2.rs @@ -42,6 +42,7 @@ #[cfg(not(target_arch = "wasm32"))] use common::block_on; use common::crash_reports::init_crash_reports; +use common::log; use common::log::LogLevel; use common::password_policy::password_policy; use mm2_core::mm_ctx::MmCtxBuilder; @@ -53,7 +54,6 @@ use lp_swap::PAYMENT_LOCKTIME; use std::sync::atomic::Ordering; use gstuff::slurp; - use serde::ser::Serialize; use serde_json::{self as json, Value as Json}; @@ -63,7 +63,6 @@ use std::process::exit; use std::ptr::null; use std::str; -mod lp_native_dex; pub use self::lp_native_dex::init_hw; pub use self::lp_native_dex::lp_init; use coins::update_coins_config; @@ -74,6 +73,7 @@ use mm2_err_handle::prelude::*; pub mod heartbeat_event; pub mod lp_dispatcher; pub mod lp_message_service; +mod lp_native_dex; pub mod lp_network; pub mod lp_ordermatch; pub mod lp_stats; @@ -159,10 +159,33 @@ pub async fn lp_main( .with_datetime(datetime.clone()) .into_mm_arc(); ctx_cb(try_s!(ctx.ffi_handle())); + + #[cfg(not(target_arch = "wasm32"))] + spawn_ctrl_c_handler(ctx.clone()); + try_s!(lp_init(ctx, version, datetime).await); Ok(()) } +/// Handles CTRL-C signals and shutdowns the KDF runtime gracefully. +/// +/// It's important to spawn this task as soon as `Ctx` is in the correct state. +#[cfg(not(target_arch = "wasm32"))] +fn spawn_ctrl_c_handler(ctx: mm2_core::mm_ctx::MmArc) { + use crate::lp_dispatcher::{dispatch_lp_event, StopCtxEvent}; + + common::executor::spawn(async move { + tokio::signal::ctrl_c() + .await + .expect("Couldn't listen for the CTRL-C signal."); + + log::info!("Wrapping things up and shutting down..."); + + dispatch_lp_event(ctx.clone(), StopCtxEvent.into()).await; + ctx.stop().await.expect("Couldn't stop the KDF runtime."); + }); +} + fn help() { const HELP_MSG: &str = r#"Command-line options. The first command-line argument is special and designates the mode. diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs index 7db7c5b02b..5ef386942c 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs @@ -21,7 +21,6 @@ use coins::{lp_coinfind, lp_coinfind_any, lp_coininit, CoinsContext, MmCoinEnum}; use common::executor::Timer; -use common::log::error; use common::{rpc_err_response, rpc_response, HyRes}; use futures::compat::Future01CompatExt; use http::Response; @@ -242,29 +241,13 @@ pub async fn my_balance(ctx: MmArc, req: Json) -> Result>, Stri Ok(try_s!(Response::builder().body(res))) } -#[cfg(not(target_arch = "wasm32"))] -async fn close_async_connection(ctx: &MmArc) { - if let Some(async_conn) = ctx.async_sqlite_connection.as_option() { - let mut conn = async_conn.lock().await; - if let Err(e) = conn.close().await { - error!("Error stopping AsyncConnection: {}", e); - } - } -} - pub async fn stop(ctx: MmArc) -> Result>, String> { dispatch_lp_event(ctx.clone(), StopCtxEvent.into()).await; // Should delay the shutdown a bit in order not to trip the "stop" RPC call in unit tests. // Stopping immediately leads to the "stop" RPC call failing with the "errno 10054" sometimes. let fut = async move { Timer::sleep(0.05).await; - - #[cfg(not(target_arch = "wasm32"))] - close_async_connection(&ctx).await; - - if let Err(e) = ctx.stop() { - error!("Error stopping MmCtx: {}", e); - } + ctx.stop().await.expect("Couldn't stop the KDF runtime."); }; // Please note we shouldn't use `MmCtx::spawner` to spawn this future, From cde7f365265a93ab2d8718a146eac498c2a46bce Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 23 Sep 2024 10:28:05 +0000 Subject: [PATCH 13/15] fix(clippy): fix coins mod clippy warnings in wasm (#2224) --- mm2src/coins/eth/eth_tests.rs | 58 +++++++--- mm2src/coins/lp_coins.rs | 4 +- .../coins/z_coin/storage/walletdb/wasm/mod.rs | 105 ++++++++++++++---- 3 files changed, 127 insertions(+), 40 deletions(-) diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index 9332594931..c20c12046e 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -1,27 +1,31 @@ use super::*; -use crate::eth::for_tests::{eth_coin_for_test, eth_coin_from_keypair}; -use crate::{DexFee, IguanaPrivKey}; -use common::{block_on, now_sec}; -#[cfg(not(target_arch = "wasm32"))] -use ethkey::{Generator, Random}; +use crate::IguanaPrivKey; +use common::block_on; use mm2_core::mm_ctx::MmCtxBuilder; -use mm2_test_helpers::for_tests::{ETH_MAINNET_CHAIN_ID, ETH_MAINNET_NODE, ETH_SEPOLIA_CHAIN_ID, ETH_SEPOLIA_NODES, + +cfg_native!( + use crate::eth::for_tests::{eth_coin_for_test, eth_coin_from_keypair}; + use crate::DexFee; + + use common::now_sec; + use ethkey::{Generator, Random}; + use mm2_test_helpers::for_tests::{ETH_MAINNET_CHAIN_ID, ETH_MAINNET_NODE, ETH_SEPOLIA_CHAIN_ID, ETH_SEPOLIA_NODES, ETH_SEPOLIA_TOKEN_CONTRACT}; -use mocktopus::mocking::*; - -/// The gas price for the tests -const GAS_PRICE: u64 = 50_000_000_000; -// `GAS_PRICE` increased by 3% -const GAS_PRICE_APPROXIMATION_ON_START_SWAP: u64 = 51_500_000_000; -// `GAS_PRICE` increased by 5% -const GAS_PRICE_APPROXIMATION_ON_ORDER_ISSUE: u64 = 52_500_000_000; -// `GAS_PRICE` increased by 7% -const GAS_PRICE_APPROXIMATION_ON_TRADE_PREIMAGE: u64 = 53_500_000_000; + use mocktopus::mocking::*; + + /// The gas price for the tests + const GAS_PRICE: u64 = 50_000_000_000; + /// `GAS_PRICE` increased by 3% + const GAS_PRICE_APPROXIMATION_ON_START_SWAP: u64 = 51_500_000_000; + /// `GAS_PRICE` increased by 5% + const GAS_PRICE_APPROXIMATION_ON_ORDER_ISSUE: u64 = 52_500_000_000; + /// `GAS_PRICE` increased by 7% + const GAS_PRICE_APPROXIMATION_ON_TRADE_PREIMAGE: u64 = 53_500_000_000; +); + // old way to add some extra gas to the returned value from gas station (non-existent now), still used in tests const GAS_PRICE_PERCENT: u64 = 10; -const TAKER_PAYMENT_SPEND_SEARCH_INTERVAL: f64 = 1.; - fn check_sum(addr: &str, expected: &str) { let actual = checksum_address(addr); assert_eq!(expected, actual); @@ -154,8 +158,11 @@ fn test_wei_from_big_decimal() { assert_eq!(expected_wei, wei); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn test_wait_for_payment_spend_timeout() { + const TAKER_PAYMENT_SPEND_SEARCH_INTERVAL: f64 = 1.; + EthCoin::spend_events.mock_safe(|_, _, _, _| MockResult::Return(Box::new(futures01::future::ok(vec![])))); EthCoin::current_block.mock_safe(|_| MockResult::Return(Box::new(futures01::future::ok(900)))); @@ -306,6 +313,7 @@ fn test_add_ten_pct_one_gwei() { assert_eq!(expected, actual); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn get_sender_trade_preimage() { /// Trade fee for the ETH coin is `2 * 150_000 * gas_price` always. @@ -361,6 +369,7 @@ fn get_sender_trade_preimage() { assert_eq!(actual, expected); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn get_erc20_sender_trade_preimage() { const APPROVE_GAS_LIMIT: u64 = 60_000; @@ -463,6 +472,7 @@ fn get_erc20_sender_trade_preimage() { ); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn get_receiver_trade_preimage() { EthCoin::get_gas_price.mock_safe(|_| MockResult::Return(Box::pin(futures::future::ok(GAS_PRICE.into())))); @@ -483,6 +493,7 @@ fn get_receiver_trade_preimage() { assert_eq!(actual, expected_fee); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn test_get_fee_to_send_taker_fee() { const DEX_FEE_AMOUNT: u64 = 100_000; @@ -533,6 +544,7 @@ fn test_get_fee_to_send_taker_fee() { /// /// Please note this test doesn't work correctly now, /// because as of now [`EthCoin::get_fee_to_send_taker_fee`] doesn't process the `Exception` web3 error correctly. +#[cfg(not(target_arch = "wasm32"))] #[test] #[ignore] fn test_get_fee_to_send_taker_fee_insufficient_balance() { @@ -562,6 +574,7 @@ fn test_get_fee_to_send_taker_fee_insufficient_balance() { ); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn validate_dex_fee_invalid_sender_eth() { let (_ctx, coin) = eth_coin_for_test(EthCoinType::Eth, &[ETH_MAINNET_NODE], None, ETH_MAINNET_CHAIN_ID); @@ -589,6 +602,7 @@ fn validate_dex_fee_invalid_sender_eth() { } } +#[cfg(not(target_arch = "wasm32"))] #[test] fn validate_dex_fee_invalid_sender_erc() { let (_ctx, coin) = eth_coin_for_test( @@ -624,6 +638,7 @@ fn validate_dex_fee_invalid_sender_erc() { } } +#[cfg(not(target_arch = "wasm32"))] fn sender_compressed_pub(tx: &SignedEthTx) -> [u8; 33] { let tx_pubkey = tx.public.unwrap(); let mut raw_pubkey = [0; 65]; @@ -633,6 +648,7 @@ fn sender_compressed_pub(tx: &SignedEthTx) -> [u8; 33] { secp_public.serialize() } +#[cfg(not(target_arch = "wasm32"))] #[test] fn validate_dex_fee_eth_confirmed_before_min_block() { let (_ctx, coin) = eth_coin_for_test(EthCoinType::Eth, &[ETH_MAINNET_NODE], None, ETH_MAINNET_CHAIN_ID); @@ -662,6 +678,7 @@ fn validate_dex_fee_eth_confirmed_before_min_block() { } } +#[cfg(not(target_arch = "wasm32"))] #[test] fn validate_dex_fee_erc_confirmed_before_min_block() { let (_ctx, coin) = eth_coin_for_test( @@ -700,6 +717,7 @@ fn validate_dex_fee_erc_confirmed_before_min_block() { } } +#[cfg(not(target_arch = "wasm32"))] #[test] fn test_negotiate_swap_contract_addr_no_fallback() { let (_, coin) = eth_coin_for_test(EthCoinType::Eth, &[ETH_MAINNET_NODE], None, ETH_MAINNET_CHAIN_ID); @@ -727,6 +745,7 @@ fn test_negotiate_swap_contract_addr_no_fallback() { assert_eq!(Some(slice.to_vec().into()), result); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn test_negotiate_swap_contract_addr_has_fallback() { let fallback = Address::from_str("0x8500AFc0bc5214728082163326C2FF0C73f4a871").unwrap(); @@ -824,6 +843,7 @@ fn polygon_check_if_my_payment_sent() { assert_eq!(expected_hash, my_payment.tx_hash_as_bytes()); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn test_message_hash() { let key_pair = Random.generate().unwrap(); @@ -842,6 +862,7 @@ fn test_message_hash() { ); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn test_sign_verify_message() { let key_pair = KeyPair::from_secret_slice( @@ -866,6 +887,7 @@ fn test_sign_verify_message() { assert!(is_valid); } +#[cfg(not(target_arch = "wasm32"))] #[test] fn test_eth_extract_secret() { let key_pair = Random.generate().unwrap(); diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 1af6027e30..500963fba8 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -124,7 +124,7 @@ macro_rules! try_f { }; } -#[cfg(feature = "enable-solana")] +#[cfg(all(feature = "enable-solana", not(target_arch = "wasm32")))] macro_rules! try_tx_fus_err { ($err: expr) => { return Box::new(futures01::future::err(crate::TransactionErr::Plain(ERRL!( @@ -133,7 +133,7 @@ macro_rules! try_tx_fus_err { }; } -#[cfg(feature = "enable-solana")] +#[cfg(all(feature = "enable-solana", not(target_arch = "wasm32")))] macro_rules! try_tx_fus_opt { ($e: expr, $err: expr) => { match $e { diff --git a/mm2src/coins/z_coin/storage/walletdb/wasm/mod.rs b/mm2src/coins/z_coin/storage/walletdb/wasm/mod.rs index 907a007c55..4c68fec22c 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wasm/mod.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wasm/mod.rs @@ -253,7 +253,12 @@ mod wasm_test { // scan the cache let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await .unwrap(); @@ -293,7 +298,12 @@ mod wasm_test { // Scan the cache again let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await .unwrap(); @@ -347,7 +357,12 @@ mod wasm_test { // Scan the cache again let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await .unwrap(); @@ -436,7 +451,12 @@ mod wasm_test { // Scan the cache again let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await .unwrap(); @@ -520,7 +540,12 @@ mod wasm_test { // Scan the cache let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await .unwrap(); @@ -545,7 +570,12 @@ mod wasm_test { // Scan the cache again let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await .unwrap(); @@ -579,7 +609,12 @@ mod wasm_test { // Scan cache let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await .unwrap(); @@ -592,7 +627,12 @@ mod wasm_test { // Scan the cache again let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); let scan = blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await .unwrap_err(); match scan.get_inner() { @@ -611,7 +651,12 @@ mod wasm_test { blockdb.insert_block(cb2.height as u32, cb2_bytes).await.unwrap(); let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); assert!(blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None + ) .await .is_ok()); @@ -650,7 +695,12 @@ mod wasm_test { // Scan the cache let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); assert!(blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None + ) .await .is_ok()); @@ -666,7 +716,12 @@ mod wasm_test { // Scan the cache again let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); assert!(blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None + ) .await .is_ok()); @@ -703,7 +758,12 @@ mod wasm_test { // Scan the cache let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); assert!(blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None + ) .await .is_ok()); @@ -728,7 +788,12 @@ mod wasm_test { // Scan the cache again let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); let scan = blockdb - .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + .process_blocks_with_mode( + consensus_params.clone(), + BlockProcessingMode::Scan(scan, None), + None, + None, + ) .await; assert!(scan.is_ok()); @@ -767,7 +832,7 @@ mod wasm_test { // // Scan the cache // let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); // assert!(blockdb - // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan, None), None, None) // .await // .is_ok()); // @@ -787,7 +852,7 @@ mod wasm_test { // // Scan the cache // let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); // assert!(blockdb - // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan, None), None, None) // .await // .is_ok()); // @@ -832,7 +897,7 @@ mod wasm_test { // // Scan the cache // let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); // assert!(blockdb - // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan, None), None, None) // .await // .is_ok()); // @@ -863,7 +928,7 @@ mod wasm_test { // // Scan the cache // let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); // assert!(blockdb - // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan, None), None, None) // .await // .is_ok()); // @@ -1033,7 +1098,7 @@ mod wasm_test { // // Scan the cache // let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); // blockdb - // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan, None), None, None) // .await // .unwrap(); // assert_eq!(walletdb.get_balance(AccountId(0)).await.unwrap(), value); @@ -1090,7 +1155,7 @@ mod wasm_test { // // Scan the cache // let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); // blockdb - // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan, None), None, None) // .await // .unwrap(); // @@ -1126,7 +1191,7 @@ mod wasm_test { // // Scan the cache // let scan = DataConnStmtCacheWrapper::new(DataConnStmtCacheWasm(walletdb.clone())); // blockdb - // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan), None, None) + // .process_blocks_with_mode(consensus_params.clone(), BlockProcessingMode::Scan(scan, None), None, None) // .await // .unwrap(); // From 4fc838838ee9aa5878bcedebc8be4dd168f4f3b5 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 23 Sep 2024 14:32:59 +0000 Subject: [PATCH 14/15] fix(native-rpc): remove escaped response body (#2219) --- mm2src/mm2_main/Cargo.toml | 3 --- mm2src/mm2_main/src/rpc.rs | 50 ++------------------------------------ 2 files changed, 2 insertions(+), 51 deletions(-) diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index 3013bce994..8f84ebb90a 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -77,9 +77,6 @@ primitives = { path = "../mm2_bitcoin/primitives" } prost = "0.11" rand = { version = "0.7", features = ["std", "small_rng"] } rand6 = { version = "0.6", package = "rand" } -# TODO: Reduce the size of regex by disabling the features we don't use. -# cf. https://github.com/rust-lang/regex/issues/583 -regex = "1" rmp-serde = "0.14.3" rpc = { path = "../mm2_bitcoin/rpc" } rpc_task = { path = "../rpc_task" } diff --git a/mm2src/mm2_main/src/rpc.rs b/mm2src/mm2_main/src/rpc.rs index 2709d76f32..1bef856e15 100644 --- a/mm2src/mm2_main/src/rpc.rs +++ b/mm2src/mm2_main/src/rpc.rs @@ -28,14 +28,11 @@ use futures::future::{join_all, FutureExt}; use http::header::{HeaderValue, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE}; use http::request::Parts; use http::{Method, Request, Response, StatusCode}; -use lazy_static::lazy_static; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_rpc::mm_protocol::{MmRpcBuilder, MmRpcResponse, MmRpcVersion}; -use regex::Regex; use serde::Serialize; use serde_json::{self as json, Value as Json}; -use std::borrow::Cow; use std::net::SocketAddr; cfg_native! { @@ -178,35 +175,6 @@ fn response_from_dispatcher_error( response.serialize_http_response() } -pub fn escape_answer<'a, S: Into>>(input: S) -> Cow<'a, str> { - lazy_static! { - static ref REGEX: Regex = Regex::new("[<>&]").unwrap(); - } - - let input = input.into(); - let mut last_match = 0; - - if REGEX.is_match(&input) { - let matches = REGEX.find_iter(&input); - let mut output = String::with_capacity(input.len()); - for mat in matches { - let (begin, end) = (mat.start(), mat.end()); - output.push_str(&input[last_match..begin]); - match &input[begin..end] { - "<" => output.push_str("<"), - ">" => output.push_str(">"), - "&" => output.push_str("&"), - _ => unreachable!(), - } - last_match = end; - } - output.push_str(&input[last_match..]); - Cow::Owned(output) - } else { - input - } -} - async fn process_single_request(ctx: MmArc, req: Json, client: SocketAddr) -> Result>, String> { let local_only = ctx.conf["rpc_local_only"].as_bool().unwrap_or(true); if req["mmrpc"].is_null() { @@ -314,23 +282,9 @@ async fn rpc_service(req: Request, ctx_h: u32, client: SocketAddr) -> Resp let res = try_sf!(process_rpc_request(ctx, req, req_json, client).await, ACCESS_CONTROL_ALLOW_ORIGIN => rpc_cors); let (mut parts, body) = res.into_parts(); - let body_escaped = { - let body_utf8 = match std::str::from_utf8(&body) { - Ok(body_utf8) => body_utf8, - Err(_) => { - return Response::builder() - .status(500) - .header(ACCESS_CONTROL_ALLOW_ORIGIN, rpc_cors) - .header(CONTENT_TYPE, APPLICATION_JSON) - .body(Body::from(err_to_rpc_json_string("Non UTF-8 output"))) - .unwrap(); - }, - }; - let escaped = escape_answer(body_utf8); - escaped.as_bytes().to_vec() - }; parts.headers.insert(ACCESS_CONTROL_ALLOW_ORIGIN, rpc_cors); - Response::from_parts(parts, Body::from(body_escaped)) + + Response::from_parts(parts, Body::from(body)) } // TODO: This should exclude TCP internals, as including them results in having to From 5c324f2cc5122bbc4a2a527941e908ccffcf6f2c Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Tue, 24 Sep 2024 11:56:02 +0300 Subject: [PATCH 15/15] chore(tests): don't use `.wait()` and use `block_on` instead (#2220) Fixes an issue regarding a tokio tcp stream that breaks because it was spawned in a non-tokio runtime. the `.wait` methods were using a different runtime - from futures - to run the future. This commit uses `block_on(fut.compat())` from KDF's tokio runtime instead. --- clippy.toml | 4 + mm2src/coins/eth/eth_tests.rs | 54 +- mm2src/coins/lightning/ln_platform.rs | 22 +- mm2src/coins/qrc20/qrc20_tests.rs | 201 +-- mm2src/coins/solana/solana_tests.rs | 6 +- mm2src/coins/tendermint/tendermint_coin.rs | 112 +- mm2src/coins/utxo/slp.rs | 5 +- mm2src/coins/utxo/utxo_tests.rs | 660 +++---- mm2src/coins/z_coin/z_coin_native_tests.rs | 25 +- mm2src/common/common.rs | 13 + mm2src/mm2_err_handle/src/map_to_mm_fut.rs | 2 +- mm2src/mm2_err_handle/src/mm_error.rs | 7 +- .../tests/docker_tests/docker_tests_common.rs | 75 +- .../tests/docker_tests/docker_tests_inner.rs | 51 +- .../tests/docker_tests/eth_docker_tests.rs | 35 +- .../tests/docker_tests/qrc20_tests.rs | 236 +-- .../tests/docker_tests/swap_proto_v2_tests.rs | 9 +- .../tests/docker_tests/swap_watcher_tests.rs | 1580 ++++++++--------- 18 files changed, 1446 insertions(+), 1651 deletions(-) create mode 100644 clippy.toml diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000000..068d7e886b --- /dev/null +++ b/clippy.toml @@ -0,0 +1,4 @@ +[[disallowed-methods]] +path = "futures::future::Future::wait" +replacement = "common::block_on_f01" +reason = "Use the default KDF async executor." \ No newline at end of file diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index c20c12046e..03705ff4ca 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -1,6 +1,6 @@ use super::*; use crate::IguanaPrivKey; -use common::block_on; +use common::{block_on, block_on_f01}; use mm2_core::mm_ctx::MmCtxBuilder; cfg_native!( @@ -191,18 +191,16 @@ fn test_wait_for_payment_spend_timeout() { 184, 42, 106, ]; - assert!(coin - .wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { - tx_bytes: &tx_bytes, - secret_hash: &[], - wait_until, - from_block, - swap_contract_address: &coin.swap_contract_address(), - check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, - watcher_reward: false - }) - .wait() - .is_err()); + assert!(block_on_f01(coin.wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { + tx_bytes: &tx_bytes, + secret_hash: &[], + wait_until, + from_block, + swap_contract_address: &coin.swap_contract_address(), + check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, + watcher_reward: false + })) + .is_err()); } #[cfg(not(target_arch = "wasm32"))] @@ -229,7 +227,7 @@ fn test_withdraw_impl_manual_fee() { memo: None, ibc_source_channel: None, }; - coin.get_balance().wait().unwrap(); + block_on_f01(coin.get_balance()).unwrap(); let tx_details = block_on(withdraw_impl(coin, withdraw_req)).unwrap(); let expected = Some( @@ -278,7 +276,7 @@ fn test_withdraw_impl_fee_details() { memo: None, ibc_source_channel: None, }; - coin.get_balance().wait().unwrap(); + block_on_f01(coin.get_balance()).unwrap(); let tx_details = block_on(withdraw_impl(coin, withdraw_req)).unwrap(); let expected = Some( @@ -486,10 +484,8 @@ fn get_receiver_trade_preimage() { paid_from_trading_vol: false, }; - let actual = coin - .get_receiver_trade_fee(FeeApproxStage::WithoutApprox) - .wait() - .expect("!get_sender_trade_fee"); + let actual = + block_on_f01(coin.get_receiver_trade_fee(FeeApproxStage::WithoutApprox)).expect("!get_sender_trade_fee"); assert_eq!(actual, expected_fee); } @@ -595,7 +591,9 @@ fn validate_dex_fee_invalid_sender_eth() { min_block_number: 0, uuid: &[], }; - let error = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let error = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("was sent from wrong address")), _ => panic!("Expected `WrongPaymentTx` wrong sender address, found {:?}", error), @@ -631,7 +629,9 @@ fn validate_dex_fee_invalid_sender_erc() { min_block_number: 0, uuid: &[], }; - let error = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let error = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("was sent from wrong address")), _ => panic!("Expected `WrongPaymentTx` wrong sender address, found {:?}", error), @@ -671,7 +671,9 @@ fn validate_dex_fee_eth_confirmed_before_min_block() { min_block_number: 11784793, uuid: &[], }; - let error = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let error = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("confirmed before min_block")), _ => panic!("Expected `WrongPaymentTx` early confirmation, found {:?}", error), @@ -710,7 +712,9 @@ fn validate_dex_fee_erc_confirmed_before_min_block() { min_block_number: 11823975, uuid: &[], }; - let error = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let error = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("confirmed before min_block")), _ => panic!("Expected `WrongPaymentTx` early confirmation, found {:?}", error), @@ -834,9 +838,7 @@ fn polygon_check_if_my_payment_sent() { amount: &BigDecimal::default(), payment_instructions: &None, }; - let my_payment = coin - .check_if_my_payment_sent(if_my_payment_sent_args) - .wait() + let my_payment = block_on_f01(coin.check_if_my_payment_sent(if_my_payment_sent_args)) .unwrap() .unwrap(); let expected_hash = BytesJson::from("69a20008cea0c15ee483b5bbdff942752634aa072dfd2ff715fe87eec302de11"); diff --git a/mm2src/coins/lightning/ln_platform.rs b/mm2src/coins/lightning/ln_platform.rs index 4d0573af95..0a5fae0a4f 100644 --- a/mm2src/coins/lightning/ln_platform.rs +++ b/mm2src/coins/lightning/ln_platform.rs @@ -15,7 +15,7 @@ use bitcoin::hash_types::{BlockHash, TxMerkleNode, Txid}; use bitcoin_hashes::{sha256d, Hash}; use common::executor::{abortable_queue::AbortableQueue, AbortableSystem, SpawnFuture, Timer}; use common::log::{debug, error, info}; -use common::wait_until_sec; +use common::{block_on_f01, wait_until_sec}; use futures::compat::Future01CompatExt; use futures::future::join_all; use keys::hash::H256; @@ -570,17 +570,15 @@ impl FeeEstimator for Platform { ConfirmationTarget::HighPriority => self.confirmations_targets.high_priority, }; let fee_per_kb = tokio::task::block_in_place(move || { - self.rpc_client() - .estimate_fee_sat( - platform_coin.decimals(), - // Todo: when implementing Native client detect_fee_method should be used for Native and - // EstimateFeeMethod::Standard for Electrum - &EstimateFeeMethod::Standard, - &conf.estimate_fee_mode, - n_blocks, - ) - .wait() - .unwrap_or(latest_fees) + block_on_f01(self.rpc_client().estimate_fee_sat( + platform_coin.decimals(), + // Todo: when implementing Native client detect_fee_method should be used for Native and + // EstimateFeeMethod::Standard for Electrum + &EstimateFeeMethod::Standard, + &conf.estimate_fee_mode, + n_blocks, + )) + .unwrap_or(latest_fees) }); // Set default fee to last known fee for the corresponding confirmation target diff --git a/mm2src/coins/qrc20/qrc20_tests.rs b/mm2src/coins/qrc20/qrc20_tests.rs index 2caf87c3bf..d77afa2f9b 100644 --- a/mm2src/coins/qrc20/qrc20_tests.rs +++ b/mm2src/coins/qrc20/qrc20_tests.rs @@ -1,6 +1,6 @@ use super::*; use crate::{DexFee, TxFeeDetails, WaitForHTLCTxSpendArgs}; -use common::{block_on, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY}; +use common::{block_on, block_on_f01, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY}; use crypto::Secp256k1Secret; use itertools::Itertools; use keys::Address; @@ -96,7 +96,7 @@ fn test_withdraw_to_p2sh_address_should_fail() { memo: None, ibc_source_channel: None, }; - let err = coin.withdraw(req).wait().unwrap_err().into_inner(); + let err = block_on_f01(coin.withdraw(req)).unwrap_err().into_inner(); let expect = WithdrawError::InvalidAddress("QRC20 can be sent to P2PKH addresses only".to_owned()); assert_eq!(err, expect); } @@ -112,19 +112,22 @@ fn test_withdraw_impl_fee_details() { let (_ctx, coin) = qrc20_coin_for_test(priv_key, None); Qrc20Coin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); let withdraw_req = WithdrawRequest { @@ -140,7 +143,7 @@ fn test_withdraw_impl_fee_details() { memo: None, ibc_source_channel: None, }; - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); let expected: Qrc20FeeDetails = json::from_value(json!({ "coin": "QTUM", @@ -287,7 +290,7 @@ fn test_wait_for_confirmations_excepted() { wait_until, check_every, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); // tx_hash: ed53b97deb2ad76974c972cb084f6ba63bd9f16c91c4a39106a20c6d14599b2a // `erc20Payment` contract call excepted @@ -299,7 +302,7 @@ fn test_wait_for_confirmations_excepted() { wait_until, check_every, }; - let error = coin.wait_for_confirmations(confirm_payment_input).wait().unwrap_err(); + let error = block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap_err(); log!("error: {:?}", error); assert!(error.contains("Contract call failed with an error: Revert")); @@ -313,7 +316,7 @@ fn test_wait_for_confirmations_excepted() { wait_until, check_every, }; - let error = coin.wait_for_confirmations(confirm_payment_input).wait().unwrap_err(); + let error = block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap_err(); log!("error: {:?}", error); assert!(error.contains("Contract call failed with an error: Revert")); } @@ -333,67 +336,59 @@ fn test_validate_fee() { let amount = BigDecimal::from_str("0.01").unwrap(); - let result = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &tx, - expected_sender: &sender_pub, - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(amount.clone().into()), - min_block_number: 0, - uuid: &[], - }) - .wait(); + let result = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &sender_pub, + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(amount.clone().into()), + min_block_number: 0, + uuid: &[], + })); assert!(result.is_ok()); let fee_addr_dif = hex::decode("03bc2c7ba671bae4a6fc835244c9762b41647b9827d4780a89a949b984a8ddcc05").unwrap(); - let err = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &tx, - expected_sender: &sender_pub, - fee_addr: &fee_addr_dif, - dex_fee: &DexFee::Standard(amount.clone().into()), - min_block_number: 0, - uuid: &[], - }) - .wait() - .expect_err("Expected an error") - .into_inner(); + let err = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &sender_pub, + fee_addr: &fee_addr_dif, + dex_fee: &DexFee::Standard(amount.clone().into()), + min_block_number: 0, + uuid: &[], + })) + .expect_err("Expected an error") + .into_inner(); log!("error: {:?}", err); match err { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("QRC20 Fee tx was sent to wrong address")), _ => panic!("Expected `WrongPaymentTx` wrong receiver address, found {:?}", err), } - let err = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &tx, - expected_sender: &DEX_FEE_ADDR_RAW_PUBKEY, - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(amount.clone().into()), - min_block_number: 0, - uuid: &[], - }) - .wait() - .expect_err("Expected an error") - .into_inner(); + let err = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &DEX_FEE_ADDR_RAW_PUBKEY, + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(amount.clone().into()), + min_block_number: 0, + uuid: &[], + })) + .expect_err("Expected an error") + .into_inner(); log!("error: {:?}", err); match err { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("was sent from wrong address")), _ => panic!("Expected `WrongPaymentTx` wrong sender address, found {:?}", err), } - let err = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &tx, - expected_sender: &sender_pub, - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(amount.clone().into()), - min_block_number: 2000000, - uuid: &[], - }) - .wait() - .expect_err("Expected an error") - .into_inner(); + let err = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &sender_pub, + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(amount.clone().into()), + min_block_number: 2000000, + uuid: &[], + })) + .expect_err("Expected an error") + .into_inner(); log!("error: {:?}", err); match err { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("confirmed before min_block")), @@ -401,18 +396,16 @@ fn test_validate_fee() { } let amount_dif = BigDecimal::from_str("0.02").unwrap(); - let err = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &tx, - expected_sender: &sender_pub, - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(amount_dif.into()), - min_block_number: 0, - uuid: &[], - }) - .wait() - .expect_err("Expected an error") - .into_inner(); + let err = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &sender_pub, + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(amount_dif.into()), + min_block_number: 0, + uuid: &[], + })) + .expect_err("Expected an error") + .into_inner(); log!("error: {:?}", err); match err { ValidatePaymentError::WrongPaymentTx(err) => { @@ -424,18 +417,16 @@ fn test_validate_fee() { // QTUM tx "8a51f0ffd45f34974de50f07c5bf2f0949da4e88433f8f75191953a442cf9310" let tx = TransactionEnum::UtxoTx("020000000113640281c9332caeddd02a8dd0d784809e1ad87bda3c972d89d5ae41f5494b85010000006a47304402207c5c904a93310b8672f4ecdbab356b65dd869a426e92f1064a567be7ccfc61ff02203e4173b9467127f7de4682513a21efb5980e66dbed4da91dff46534b8e77c7ef012102baefe72b3591de2070c0da3853226b00f082d72daa417688b61cb18c1d543d1afeffffff020001b2c4000000001976a9149e032d4b0090a11dc40fe6c47601499a35d55fbb88acbc4dd20c2f0000001976a9144208fa7be80dcf972f767194ad365950495064a488ac76e70800".into()); let sender_pub = hex::decode("02baefe72b3591de2070c0da3853226b00f082d72daa417688b61cb18c1d543d1a").unwrap(); - let err = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &tx, - expected_sender: &sender_pub, - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(amount.into()), - min_block_number: 0, - uuid: &[], - }) - .wait() - .expect_err("Expected an error") - .into_inner(); + let err = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &sender_pub, + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(amount.into()), + min_block_number: 0, + uuid: &[], + })) + .expect_err("Expected an error") + .into_inner(); log!("error: {:?}", err); match err { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("Expected 'transfer' contract call")), @@ -462,18 +453,16 @@ fn test_wait_for_tx_spend_malicious() { let payment_tx = hex::decode("01000000016601daa208531d20532c460d0c86b74a275f4a126bbffcf4eafdf33835af2859010000006a47304402205825657548bc1b5acf3f4bb2f89635a02b04f3228cd08126e63c5834888e7ac402207ca05fa0a629a31908a97a508e15076e925f8e621b155312b7526a6666b06a76012103693bff1b39e8b5a306810023c29b95397eb395530b106b1820ea235fd81d9ce9ffffffff020000000000000000e35403a0860101284cc49b415b2a8620ad3b72361a5aeba5dffd333fb64750089d935a1ec974d6a91ef4f24ff6ba0000000000000000000000000000000000000000000000000000000001312d00000000000000000000000000d362e096e873eb7907e205fadc6175c6fec7bc44000000000000000000000000783cf0be521101942da509846ea476e683aad8324b6b2e5444c2639cc0fb7bcea5afba3f3cdce239000000000000000000000000000000000000000000000000000000000000000000000000000000005f855c7614ba8b71f3544b93e2f681f996da519a98ace0107ac2203de400000000001976a9149e032d4b0090a11dc40fe6c47601499a35d55fbb88ac415d855f").unwrap(); let wait_until = now_sec() + 1; let from_block = 696245; - let found = coin - .wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { - tx_bytes: &payment_tx, - secret_hash: &[], - wait_until, - from_block, - swap_contract_address: &coin.swap_contract_address(), - check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, - watcher_reward: false, - }) - .wait() - .unwrap(); + let found = block_on_f01(coin.wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { + tx_bytes: &payment_tx, + secret_hash: &[], + wait_until, + from_block, + swap_contract_address: &coin.swap_contract_address(), + check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, + watcher_reward: false, + })) + .unwrap(); let spend_tx = match found { TransactionEnum::UtxoTx(tx) => tx, @@ -731,7 +720,7 @@ fn test_get_trade_fee() { // check if the coin's tx fee is expected check_tx_fee(&coin, ActualTxFee::FixedPerKb(EXPECTED_TX_FEE as u64)); - let actual_trade_fee = coin.get_trade_fee().wait().unwrap(); + let actual_trade_fee = block_on_f01(coin.get_trade_fee()).unwrap(); let expected_trade_fee_amount = big_decimal_from_sat( 2 * CONTRACT_CALL_GAS_FEE + SWAP_PAYMENT_GAS_FEE + EXPECTED_TX_FEE, coin.utxo.decimals, @@ -905,10 +894,8 @@ fn test_receiver_trade_preimage() { // check if the coin's tx fee is expected check_tx_fee(&coin, ActualTxFee::FixedPerKb(EXPECTED_TX_FEE as u64)); - let actual = coin - .get_receiver_trade_fee(FeeApproxStage::WithoutApprox) - .wait() - .expect("!get_receiver_trade_fee"); + let actual = + block_on_f01(coin.get_receiver_trade_fee(FeeApproxStage::WithoutApprox)).expect("!get_receiver_trade_fee"); // only one contract call should be included into the expected trade fee let expected_receiver_fee = big_decimal_from_sat(CONTRACT_CALL_GAS_FEE + EXPECTED_TX_FEE, coin.utxo.decimals); let expected = TradeFee { @@ -935,7 +922,7 @@ fn test_taker_fee_tx_fee() { spendable: BigDecimal::from(5u32), unspendable: BigDecimal::from(0u32), }; - assert_eq!(coin.my_balance().wait().expect("!my_balance"), expected_balance); + assert_eq!(block_on_f01(coin.my_balance()).expect("!my_balance"), expected_balance); let dex_fee_amount = BigDecimal::from(5u32); let actual = block_on(coin.get_fee_to_send_taker_fee( diff --git a/mm2src/coins/solana/solana_tests.rs b/mm2src/coins/solana/solana_tests.rs index fe2b104293..d4126f35c0 100644 --- a/mm2src/coins/solana/solana_tests.rs +++ b/mm2src/coins/solana/solana_tests.rs @@ -1,5 +1,5 @@ use base58::ToBase58; -use common::{block_on, Future01CompatExt}; +use common::{block_on, block_on_f01, Future01CompatExt}; use rpc::v1::types::Bytes; use solana_client::rpc_request::TokenAccountsFilter; use solana_sdk::{bs58, @@ -367,7 +367,7 @@ fn solana_coin_send_and_refund_maker_payment() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_maker_payment(args).wait().unwrap(); + let tx = block_on_f01(coin.send_maker_payment(args)).unwrap(); log!("swap tx {:?}", tx); let refund_args = RefundPaymentArgs { @@ -415,7 +415,7 @@ fn solana_coin_send_and_spend_maker_payment() { wait_for_confirmation_until: 0, }; - let tx = coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let tx = block_on_f01(coin.send_maker_payment(maker_payment_args)).unwrap(); log!("swap tx {:?}", tx); let maker_pub = taker_pub; diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index bc5e12f6ff..9c7a1c1d96 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -3313,7 +3313,7 @@ fn parse_expected_sequence_number(e: &str) -> MmResult { @@ -3725,18 +3723,16 @@ pub mod tendermint_coin_tests { data: TxRaw::decode(random_transfer_tx_bytes.as_slice()).unwrap(), }); - let error = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &random_transfer_tx, - expected_sender: &[], - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(invalid_amount.clone()), - min_block_number: 0, - uuid: &[1; 16], - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &random_transfer_tx, + expected_sender: &[], + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(invalid_amount.clone()), + min_block_number: 0, + uuid: &[1; 16], + })) + .unwrap_err() + .into_inner(); println!("{}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("sent to wrong address")), @@ -3758,18 +3754,16 @@ pub mod tendermint_coin_tests { data: TxRaw::decode(dex_fee_tx.encode_to_vec().as_slice()).unwrap(), }); - let error = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &dex_fee_tx, - expected_sender: &[], - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(invalid_amount), - min_block_number: 0, - uuid: &[1; 16], - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &dex_fee_tx, + expected_sender: &[], + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(invalid_amount), + min_block_number: 0, + uuid: &[1; 16], + })) + .unwrap_err() + .into_inner(); println!("{}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("Invalid amount")), @@ -3778,18 +3772,16 @@ pub mod tendermint_coin_tests { let valid_amount: BigDecimal = "0.0001".parse().unwrap(); // valid amount but invalid sender - let error = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &dex_fee_tx, - expected_sender: &DEX_FEE_ADDR_RAW_PUBKEY, - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(valid_amount.clone().into()), - min_block_number: 0, - uuid: &[1; 16], - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &dex_fee_tx, + expected_sender: &DEX_FEE_ADDR_RAW_PUBKEY, + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(valid_amount.clone().into()), + min_block_number: 0, + uuid: &[1; 16], + })) + .unwrap_err() + .into_inner(); println!("{}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("Invalid sender")), @@ -3797,18 +3789,16 @@ pub mod tendermint_coin_tests { } // invalid memo - let error = coin - .validate_fee(ValidateFeeArgs { - fee_tx: &dex_fee_tx, - expected_sender: &pubkey, - fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, - dex_fee: &DexFee::Standard(valid_amount.into()), - min_block_number: 0, - uuid: &[1; 16], - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(coin.validate_fee(ValidateFeeArgs { + fee_tx: &dex_fee_tx, + expected_sender: &pubkey, + fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, + dex_fee: &DexFee::Standard(valid_amount.into()), + min_block_number: 0, + uuid: &[1; 16], + })) + .unwrap_err() + .into_inner(); println!("{}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("Invalid memo")), diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index c559449c22..503611445e 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1945,6 +1945,7 @@ mod slp_tests { use crate::utxo::GetUtxoListOps; use crate::{utxo::bch::tbch_coin_for_test, TransactionErr}; use common::block_on; + use common::block_on_f01; use mocktopus::mocking::{MockResult, Mockable}; use std::mem::discriminant; @@ -2206,11 +2207,11 @@ mod slp_tests { ]; let tx_bytes_str = hex::encode(tx_bytes); - let err = fusd.send_raw_tx(&tx_bytes_str).wait().unwrap_err(); + let err = block_on_f01(fusd.send_raw_tx(&tx_bytes_str)).unwrap_err(); println!("{:?}", err); assert!(err.contains("is not valid with reason outputs greater than inputs")); - let err2 = fusd.send_raw_tx_bytes(tx_bytes).wait().unwrap_err(); + let err2 = block_on_f01(fusd.send_raw_tx_bytes(tx_bytes)).unwrap_err(); println!("{:?}", err2); assert!(err2.contains("is not valid with reason outputs greater than inputs")); assert_eq!(err, err2); diff --git a/mm2src/coins/utxo/utxo_tests.rs b/mm2src/coins/utxo/utxo_tests.rs index 868f558f1f..9456361c64 100644 --- a/mm2src/coins/utxo/utxo_tests.rs +++ b/mm2src/coins/utxo/utxo_tests.rs @@ -34,13 +34,12 @@ use crate::{BlockHeightAndTime, CoinBalance, ConfirmPaymentInput, DexFee, Iguana use crate::{WaitForHTLCTxSpendArgs, WithdrawFee}; use chain::{BlockHeader, BlockHeaderBits, OutPoint}; use common::executor::Timer; -use common::{block_on, wait_until_sec, OrdRange, PagingOptionsEnum, DEX_FEE_ADDR_RAW_PUBKEY}; +use common::{block_on, block_on_f01, wait_until_sec, OrdRange, PagingOptionsEnum, DEX_FEE_ADDR_RAW_PUBKEY}; use crypto::{privkey::key_pair_from_seed, Bip44Chain, HDPathToAccount, RpcDerivationPath, Secp256k1Secret}; #[cfg(not(target_arch = "wasm32"))] use db_common::sqlite::rusqlite::Connection; use futures::channel::mpsc::channel; -use futures::future::join_all; -use futures::TryFutureExt; +use futures::future::{join_all, Either, FutureExt, TryFutureExt}; use keys::prefixes::*; use mm2_core::mm_ctx::MmCtxBuilder; use mm2_number::bigdecimal::{BigDecimal, Signed}; @@ -438,18 +437,16 @@ fn test_wait_for_payment_spend_timeout_native() { let wait_until = now_sec() - 1; let from_block = 1000; - assert!(coin - .wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { - tx_bytes: &transaction, - secret_hash: &[], - wait_until, - from_block, - swap_contract_address: &None, - check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, - watcher_reward: false - }) - .wait() - .is_err()); + assert!(block_on_f01(coin.wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { + tx_bytes: &transaction, + secret_hash: &[], + wait_until, + from_block, + swap_contract_address: &None, + check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, + watcher_reward: false + })) + .is_err()); assert!(unsafe { OUTPUT_SPEND_CALLED }); } @@ -486,18 +483,16 @@ fn test_wait_for_payment_spend_timeout_electrum() { let wait_until = now_sec() - 1; let from_block = 1000; - assert!(coin - .wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { - tx_bytes: &transaction, - secret_hash: &[], - wait_until, - from_block, - swap_contract_address: &None, - check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, - watcher_reward: false - }) - .wait() - .is_err()); + assert!(block_on_f01(coin.wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { + tx_bytes: &transaction, + secret_hash: &[], + wait_until, + from_block, + swap_contract_address: &None, + check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, + watcher_reward: false + })) + .is_err()); assert!(unsafe { OUTPUT_SPEND_CALLED }); } @@ -575,19 +570,22 @@ fn test_search_for_swap_tx_spend_electrum_was_refunded() { #[cfg(not(target_arch = "wasm32"))] fn test_withdraw_impl_set_fixed_fee() { UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); let client = NativeClient(Arc::new(NativeClientImpl::default())); @@ -613,7 +611,7 @@ fn test_withdraw_impl_set_fixed_fee() { } .into(), ); - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); assert_eq!(expected, tx_details.fee_details); } @@ -621,19 +619,22 @@ fn test_withdraw_impl_set_fixed_fee() { #[cfg(not(target_arch = "wasm32"))] fn test_withdraw_impl_sat_per_kb_fee() { UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); let client = NativeClient(Arc::new(NativeClientImpl::default())); @@ -662,7 +663,7 @@ fn test_withdraw_impl_sat_per_kb_fee() { } .into(), ); - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); assert_eq!(expected, tx_details.fee_details); } @@ -670,19 +671,22 @@ fn test_withdraw_impl_sat_per_kb_fee() { #[cfg(not(target_arch = "wasm32"))] fn test_withdraw_impl_sat_per_kb_fee_amount_equal_to_max() { UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); let client = NativeClient(Arc::new(NativeClientImpl::default())); @@ -701,7 +705,7 @@ fn test_withdraw_impl_sat_per_kb_fee_amount_equal_to_max() { memo: None, ibc_source_channel: None, }; - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); // The resulting transaction size might be 210 or 211 bytes depending on signature size // MM2 always expects the worst case during fee calculation // 0.1 * 211 / 1000 = 0.0211 @@ -721,19 +725,22 @@ fn test_withdraw_impl_sat_per_kb_fee_amount_equal_to_max() { #[cfg(not(target_arch = "wasm32"))] fn test_withdraw_impl_sat_per_kb_fee_amount_equal_to_max_dust_included_to_fee() { UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); let client = NativeClient(Arc::new(NativeClientImpl::default())); @@ -752,7 +759,7 @@ fn test_withdraw_impl_sat_per_kb_fee_amount_equal_to_max_dust_included_to_fee() memo: None, ibc_source_channel: None, }; - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); // The resulting transaction size might be 210 or 211 bytes depending on signature size // MM2 always expects the worst case during fee calculation // 0.1 * 211 / 1000 = 0.0211 @@ -772,19 +779,22 @@ fn test_withdraw_impl_sat_per_kb_fee_amount_equal_to_max_dust_included_to_fee() #[cfg(not(target_arch = "wasm32"))] fn test_withdraw_impl_sat_per_kb_fee_amount_over_max() { UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); let client = NativeClient(Arc::new(NativeClientImpl::default())); @@ -803,26 +813,29 @@ fn test_withdraw_impl_sat_per_kb_fee_amount_over_max() { memo: None, ibc_source_channel: None, }; - coin.withdraw(withdraw_req).wait().unwrap_err(); + block_on_f01(coin.withdraw(withdraw_req)).unwrap_err(); } #[test] #[cfg(not(target_arch = "wasm32"))] fn test_withdraw_impl_sat_per_kb_fee_max() { UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); let client = NativeClient(Arc::new(NativeClientImpl::default())); @@ -851,7 +864,7 @@ fn test_withdraw_impl_sat_per_kb_fee_max() { } .into(), ); - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); assert_eq!(expected, tx_details.fee_details); } @@ -866,20 +879,23 @@ fn test_withdraw_kmd_rewards_impl( let verbose: RpcTransaction = json::from_str(verbose_serialized).unwrap(); let unspent_height = verbose.height; UtxoStandardCoin::get_unspent_ordered_list.mock_safe(move |coin: &UtxoStandardCoin, _| { - let tx: UtxoTx = tx_hex.into(); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: tx.hash(), - index: 0, - }, - value: tx.outputs[0].value, - height: unspent_height, - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let tx: UtxoTx = tx_hex.into(); + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: tx.hash(), + index: 0, + }, + value: tx.outputs[0].value, + height: unspent_height, + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); UtxoStandardCoin::get_current_mtp .mock_safe(move |_fields| MockResult::Return(Box::pin(futures::future::ok(current_mtp)))); @@ -909,7 +925,7 @@ fn test_withdraw_kmd_rewards_impl( coin: Some("KMD".into()), amount: "0.00001".parse().unwrap(), }); - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); assert_eq!(tx_details.fee_details, Some(expected_fee)); let expected_rewards = expected_rewards.map(|amount| KmdRewardsDetails { @@ -958,20 +974,23 @@ fn test_withdraw_rick_rewards_none() { const TX_HEX: &str = "0400008085202f8901df8119c507aa61d32332cd246dbfeb3818a4f96e76492454c1fbba5aa097977e000000004847304402205a7e229ea6929c97fd6dde254c19e4eb890a90353249721701ae7a1c477d99c402206a8b7c5bf42b5095585731d6b4c589ce557f63c20aed69ff242eca22ecfcdc7a01feffffff02d04d1bffbc050000232102afdbba3e3c90db5f0f4064118f79cf308f926c68afd64ea7afc930975663e4c4ac402dd913000000001976a9143e17014eca06281ee600adffa34b4afb0922a22288ac2bdab86035a00e000000000000000000000000"; UtxoStandardCoin::get_unspent_ordered_list.mock_safe(move |coin, _| { - let tx: UtxoTx = TX_HEX.into(); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: tx.hash(), - index: 0, - }, - value: tx.outputs[0].value, - height: Some(1431628), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let tx: UtxoTx = TX_HEX.into(); + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: tx.hash(), + index: 0, + }, + value: tx.outputs[0].value, + height: Some(1431628), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); let withdraw_req = WithdrawRequest { @@ -988,7 +1007,7 @@ fn test_withdraw_rick_rewards_none() { coin: Some(TEST_COIN_NAME.into()), amount: "0.00001".parse().unwrap(), }); - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); assert_eq!(tx_details.fee_details, Some(expected_fee)); assert_eq!(tx_details.kmd_rewards, None); } @@ -1066,7 +1085,7 @@ fn test_electrum_rpc_client_error() { let client = electrum_client_for_test(&["electrum1.cipig.net:10060"]); let empty_hash = H256Json::default(); - let err = client.get_verbose_transaction(&empty_hash).wait().unwrap_err(); + let err = block_on_f01(client.get_verbose_transaction(&empty_hash)).unwrap_err(); // use the static string instead because the actual error message cannot be obtain // by serde_json serialization @@ -1305,10 +1324,7 @@ fn test_get_median_time_past_from_electrum_kmd() { "electrum3.cipig.net:10001", ]); - let mtp = client - .get_median_time_past(1773390, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard) - .wait() - .unwrap(); + let mtp = block_on_f01(client.get_median_time_past(1773390, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard)).unwrap(); // the MTP is block time of 1773385 in this case assert_eq!(1583159915, mtp); } @@ -1321,10 +1337,7 @@ fn test_get_median_time_past_from_electrum_btc() { "electrum3.cipig.net:10000", ]); - let mtp = client - .get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard) - .wait() - .unwrap(); + let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard)).unwrap(); assert_eq!(1591173041, mtp); } @@ -1348,10 +1361,7 @@ fn test_get_median_time_past_from_native_has_median_in_get_block() { ) }); - let mtp = client - .get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard) - .wait() - .unwrap(); + let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard)).unwrap(); assert_eq!(1591173041, mtp); } @@ -1394,10 +1404,7 @@ fn test_get_median_time_past_from_native_does_not_have_median_in_get_block() { MockResult::Return(Box::new(futures01::future::ok(block))) }); - let mtp = client - .get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard) - .wait() - .unwrap(); + let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard)).unwrap(); assert_eq!(1591173041, mtp); } @@ -1597,13 +1604,11 @@ fn test_spam_rick() { fn test_one_unavailable_electrum_proto_version() { // check if the electrum-mona.bitbank.cc:50001 doesn't support the protocol version 1.4 let client = electrum_client_for_test(&["electrum-mona.bitbank.cc:50001"]); - let result = client - .server_version( - "electrum-mona.bitbank.cc:50001", - "AtomicDEX", - &OrdRange::new(1.4, 1.4).unwrap(), - ) - .wait(); + let result = block_on_f01(client.server_version( + "electrum-mona.bitbank.cc:50001", + "AtomicDEX", + &OrdRange::new(1.4, 1.4).unwrap(), + )); assert!(result .err() .unwrap() @@ -1628,7 +1633,7 @@ fn test_one_unavailable_electrum_proto_version() { block_on(async { Timer::sleep(0.5).await }); - assert!(coin.as_ref().rpc_client.get_block_count().wait().is_ok()); + assert!(block_on_f01(coin.as_ref().rpc_client.get_block_count()).is_ok()); } #[test] @@ -1685,7 +1690,7 @@ fn test_qtum_add_delegation() { address: address.to_string(), fee: Some(10), }; - let res = coin.add_delegation(request).wait().unwrap(); + let res = block_on_f01(coin.add_delegation(request)).unwrap(); // Eligible for delegation assert!(res.my_balance_change.is_negative()); assert_eq!(res.total_amount, res.spent_by_me); @@ -1695,7 +1700,7 @@ fn test_qtum_add_delegation() { address: "fake_address".to_string(), fee: Some(10), }; - let res = coin.add_delegation(request).wait(); + let res = block_on_f01(coin.add_delegation(request)); // Wrong address assert!(res.is_err()); } @@ -1728,7 +1733,7 @@ fn test_qtum_add_delegation_on_already_delegating() { address: address.to_string(), fee: Some(10), }; - let res = coin.add_delegation(request).wait(); + let res = block_on_f01(coin.add_delegation(request)); // Already Delegating assert!(res.is_err()); } @@ -1754,7 +1759,7 @@ fn test_qtum_get_delegation_infos() { keypair.private().secret, )) .unwrap(); - let staking_infos = coin.get_delegation_infos().wait().unwrap(); + let staking_infos = block_on_f01(coin.get_delegation_infos()).unwrap(); match staking_infos.staking_infos_details { StakingInfosDetails::Qtum(staking_details) => { assert!(staking_details.am_i_staking); @@ -1784,49 +1789,49 @@ fn test_qtum_remove_delegation() { keypair.private().secret, )) .unwrap(); - let res = coin.remove_delegation().wait(); + let res = block_on_f01(coin.remove_delegation()); assert!(res.is_ok()); } #[test] fn test_qtum_my_balance() { QtumCoin::get_mature_unspent_ordered_list.mock_safe(move |coin, _address| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - // spendable balance (66.0) - let mature = vec![ - UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + // spendable balance (66.0) + let mature = vec![ + UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 5000000000, + height: Default::default(), + script: Vec::new().into(), }, - value: 5000000000, - height: Default::default(), - script: Vec::new().into(), - }, - UnspentInfo { + UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1600000000, + height: Default::default(), + script: Vec::new().into(), + }, + ]; + // unspendable (2.0) + let immature = vec![UnspentInfo { outpoint: OutPoint { hash: 1.into(), index: 0, }, - value: 1600000000, + value: 200000000, height: Default::default(), script: Vec::new().into(), - }, - ]; - // unspendable (2.0) - let immature = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 200000000, - height: Default::default(), - script: Vec::new().into(), - }]; - MockResult::Return(Box::pin(futures::future::ok(( - MatureUnspentList { mature, immature }, - cache, - )))) + }]; + Ok((MatureUnspentList { mature, immature }, cache)) + }; + MockResult::Return(fut.boxed()) }); let conf = json!({"coin":"tQTUM","rpcport":13889,"pubtype":120,"p2shtype":110}); @@ -1845,7 +1850,7 @@ fn test_qtum_my_balance() { let params = UtxoActivationParams::from_legacy_req(&req).unwrap(); let coin = block_on(qtum_coin_with_priv_key(&ctx, "tQTUM", &conf, ¶ms, priv_key)).unwrap(); - let CoinBalance { spendable, unspendable } = coin.my_balance().wait().unwrap(); + let CoinBalance { spendable, unspendable } = block_on_f01(coin.my_balance()).unwrap(); let expected_spendable = BigDecimal::from(66); let expected_unspendable = BigDecimal::from(2); assert_eq!(spendable, expected_spendable); @@ -1881,7 +1886,7 @@ fn test_qtum_my_balance_with_check_utxo_maturity_false() { let params = UtxoActivationParams::from_legacy_req(&req).unwrap(); let coin = block_on(qtum_coin_with_priv_key(&ctx, "tQTUM", &conf, ¶ms, priv_key)).unwrap(); - let CoinBalance { spendable, unspendable } = coin.my_balance().wait().unwrap(); + let CoinBalance { spendable, unspendable } = block_on_f01(coin.my_balance()).unwrap(); let expected_spendable = BigDecimal::from(DISPLAY_BALANCE); let expected_unspendable = BigDecimal::from(0); assert_eq!(spendable, expected_spendable); @@ -1899,7 +1904,7 @@ fn test_get_mature_unspent_ordered_map_from_cache_impl( const TX_HASH: &str = "b43f9ed47f7b97d4766b6f1614136fa0c55b9a52c97342428333521fa13ad714"; let tx_hash: H256Json = hex::decode(TX_HASH).unwrap().as_slice().into(); let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); - let mut verbose = client.get_verbose_transaction(&tx_hash).wait().unwrap(); + let mut verbose = block_on_f01(client.get_verbose_transaction(&tx_hash)).unwrap(); verbose.confirmations = cached_confs; verbose.height = cached_height; @@ -2517,15 +2522,13 @@ fn test_find_output_spend_skips_conflicting_transactions() { let tx: UtxoTx = "0400008085202f89027f57730fcbbc2c72fb18bcc3766a713044831a117bb1cade3ed88644864f7333020000006a47304402206e3737b2fcf078b61b16fa67340cc3e79c5d5e2dc9ffda09608371552a3887450220460a332aa1b8ad8f2de92d319666f70751078b221199951f80265b4f7cef8543012102d8c948c6af848c588517288168faa397d6ba3ea924596d03d1d84f224b5123c2ffffffff42b916a80430b80a77e114445b08cf120735447a524de10742fac8f6a9d4170f000000006a473044022004aa053edafb9d161ea8146e0c21ed1593aa6b9404dd44294bcdf920a1695fd902202365eac15dbcc5e9f83e2eed56a8f2f0e5aded36206f9c3fabc668fd4665fa2d012102d8c948c6af848c588517288168faa397d6ba3ea924596d03d1d84f224b5123c2ffffffff03547b16000000000017a9143e8ad0e2bf573d32cb0b3d3a304d9ebcd0c2023b870000000000000000166a144e2b3c0323ab3c2dc6f86dc5ec0729f11e42f56103970400000000001976a91450f4f098306f988d8843004689fae28c83ef16e888ac89c5925f000000000000000000000000000000".into(); let vout = 0; let from_block = 0; - let actual = client - .find_output_spend( - tx.hash(), - &tx.outputs[vout].script_pubkey, - vout, - BlockHashOrHeight::Height(from_block), - TxHashAlgo::DSHA256, - ) - .wait(); + let actual = block_on_f01(client.find_output_spend( + tx.hash(), + &tx.outputs[vout].script_pubkey, + vout, + BlockHashOrHeight::Height(from_block), + TxHashAlgo::DSHA256, + )); assert_eq!(actual, Ok(None)); assert_eq!(unsafe { GET_RAW_TRANSACTION_BYTES_CALLED }, 1); } @@ -2609,7 +2612,7 @@ fn test_get_sender_trade_fee_dynamic_tx_fee() { ); coin_fields.tx_fee = TxFee::Dynamic(EstimateFeeMethod::Standard); let coin = utxo_coin_from_fields(coin_fields); - let my_balance = coin.my_spendable_balance().wait().expect("!my_balance"); + let my_balance = block_on_f01(coin.my_spendable_balance()).expect("!my_balance"); let expected_balance = BigDecimal::from_str("2.22222").expect("!BigDecimal::from_str"); assert_eq!(my_balance, expected_balance); @@ -2657,7 +2660,9 @@ fn test_validate_fee_wrong_sender() { min_block_number: 0, uuid: &[], }; - let error = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let error = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains(INVALID_SENDER_ERR_LOG)), @@ -2682,7 +2687,9 @@ fn test_validate_fee_min_block() { min_block_number: 278455, uuid: &[], }; - let error = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let error = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); match error { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("confirmed before min_block")), _ => panic!("Expected `WrongPaymentTx` early confirmation, found {:?}", error), @@ -2711,7 +2718,7 @@ fn test_validate_fee_bch_70_bytes_signature() { min_block_number: 0, uuid: &[], }; - coin.validate_fee(validate_fee_args).wait().unwrap(); + block_on_f01(coin.validate_fee(validate_fee_args)).unwrap(); } #[test] @@ -2766,7 +2773,7 @@ fn firo_lelantus_tx() { "electrumx02.firo.org:50001", "electrumx03.firo.org:50001", ]); - let _tx = electrum.get_verbose_transaction(&tx_hash).wait().unwrap(); + let _tx = block_on_f01(electrum.get_verbose_transaction(&tx_hash)).unwrap(); } #[test] @@ -2903,9 +2910,7 @@ fn doge_mtp() { "electrum2.cipig.net:10060", "electrum3.cipig.net:10060", ]); - let mtp = electrum - .get_median_time_past(3631820, NonZeroU64::new(11).unwrap(), CoinVariant::Standard) - .wait() + let mtp = block_on_f01(electrum.get_median_time_past(3631820, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) .unwrap(); assert_eq!(mtp, 1614849084); } @@ -2917,9 +2922,7 @@ fn firo_mtp() { "electrumx02.firo.org:50001", "electrumx03.firo.org:50001", ]); - let mtp = electrum - .get_median_time_past(356730, NonZeroU64::new(11).unwrap(), CoinVariant::Standard) - .wait() + let mtp = block_on_f01(electrum.get_median_time_past(356730, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) .unwrap(); assert_eq!(mtp, 1616492629); } @@ -2927,9 +2930,7 @@ fn firo_mtp() { #[test] fn verus_mtp() { let electrum = electrum_client_for_test(&["el0.verus.io:17485", "el1.verus.io:17485", "el2.verus.io:17485"]); - let mtp = electrum - .get_median_time_past(1480113, NonZeroU64::new(11).unwrap(), CoinVariant::Standard) - .wait() + let mtp = block_on_f01(electrum.get_median_time_past(1480113, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) .unwrap(); assert_eq!(mtp, 1618579909); } @@ -2941,9 +2942,7 @@ fn sys_mtp() { "electrum2.cipig.net:10064", "electrum3.cipig.net:10064", ]); - let mtp = electrum - .get_median_time_past(1006678, NonZeroU64::new(11).unwrap(), CoinVariant::Standard) - .wait() + let mtp = block_on_f01(electrum.get_median_time_past(1006678, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) .unwrap(); assert_eq!(mtp, 1620019628); } @@ -2955,9 +2954,7 @@ fn btc_mtp() { "electrum2.cipig.net:10000", "electrum3.cipig.net:10000", ]); - let mtp = electrum - .get_median_time_past(681659, NonZeroU64::new(11).unwrap(), CoinVariant::Standard) - .wait() + let mtp = block_on_f01(electrum.get_median_time_past(681659, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) .unwrap(); assert_eq!(mtp, 1620019527); } @@ -2969,9 +2966,7 @@ fn rvn_mtp() { "electrum2.cipig.net:10051", "electrum3.cipig.net:10051", ]); - let mtp = electrum - .get_median_time_past(1968120, NonZeroU64::new(11).unwrap(), CoinVariant::Standard) - .wait() + let mtp = block_on_f01(electrum.get_median_time_past(1968120, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) .unwrap(); assert_eq!(mtp, 1633946264); } @@ -2983,10 +2978,8 @@ fn qtum_mtp() { "electrum2.cipig.net:10050", "electrum3.cipig.net:10050", ]); - let mtp = electrum - .get_median_time_past(681659, NonZeroU64::new(11).unwrap(), CoinVariant::Qtum) - .wait() - .unwrap(); + let mtp = + block_on_f01(electrum.get_median_time_past(681659, NonZeroU64::new(11).unwrap(), CoinVariant::Qtum)).unwrap(); assert_eq!(mtp, 1598854128); } @@ -2997,9 +2990,7 @@ fn zer_mtp() { "electrum2.cipig.net:10065", "electrum3.cipig.net:10065", ]); - let mtp = electrum - .get_median_time_past(1130915, NonZeroU64::new(11).unwrap(), CoinVariant::Standard) - .wait() + let mtp = block_on_f01(electrum.get_median_time_past(1130915, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) .unwrap(); assert_eq!(mtp, 1623240214); } @@ -3196,7 +3187,7 @@ fn test_withdraw_to_p2pk_fails() { }; assert!(matches!( - coin.withdraw(withdraw_req).wait().unwrap_err().into_inner(), + block_on_f01(coin.withdraw(withdraw_req)).unwrap_err().into_inner(), WithdrawError::InvalidAddress(..) )) } @@ -3209,19 +3200,22 @@ fn test_withdraw_to_p2pkh() { let coin = utxo_coin_for_test(UtxoRpcClientEnum::Native(client), None, false); UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); // Create a p2pkh address for the test coin @@ -3249,7 +3243,7 @@ fn test_withdraw_to_p2pkh() { memo: None, ibc_source_channel: None, }; - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); let transaction: UtxoTx = deserialize(tx_details.tx.tx_hex().unwrap().as_slice()).unwrap(); let output_script: Script = transaction.outputs[0].script_pubkey.clone().into(); @@ -3266,19 +3260,22 @@ fn test_withdraw_to_p2sh() { let coin = utxo_coin_for_test(UtxoRpcClientEnum::Native(client), None, false); UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); // Create a p2sh address for the test coin @@ -3306,7 +3303,7 @@ fn test_withdraw_to_p2sh() { memo: None, ibc_source_channel: None, }; - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); let transaction: UtxoTx = deserialize(tx_details.tx.tx_hex().unwrap().as_slice()).unwrap(); let output_script: Script = transaction.outputs[0].script_pubkey.clone().into(); @@ -3323,19 +3320,22 @@ fn test_withdraw_to_p2wpkh() { let coin = utxo_coin_for_test(UtxoRpcClientEnum::Native(client), None, true); UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - script: coin - .script_for_address(&block_on(coin.as_ref().derivation_method.unwrap_single_addr())) - .unwrap(), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + script: coin + .script_for_address(&coin.as_ref().derivation_method.unwrap_single_addr().await) + .unwrap(), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); // Create a p2wpkh address for the test coin @@ -3363,7 +3363,7 @@ fn test_withdraw_to_p2wpkh() { memo: None, ibc_source_channel: None, }; - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); let transaction: UtxoTx = deserialize(tx_details.tx.tx_hex().unwrap().as_slice()).unwrap(); let output_script: Script = transaction.outputs[0].script_pubkey.clone().into(); @@ -3380,22 +3380,29 @@ fn test_withdraw_p2pk_balance() { let coin = utxo_coin_for_test(UtxoRpcClientEnum::Native(client), None, false); UtxoStandardCoin::get_unspent_ordered_list.mock_safe(|coin, _| { - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = vec![UnspentInfo { - outpoint: OutPoint { - hash: 1.into(), - index: 0, - }, - value: 1000000000, - height: Default::default(), - // Use a p2pk output script for this UTXO - script: output_script_p2pk( - &block_on(coin.as_ref().derivation_method.unwrap_single_addr()) - .pubkey() - .unwrap(), - ), - }]; - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = vec![UnspentInfo { + outpoint: OutPoint { + hash: 1.into(), + index: 0, + }, + value: 1000000000, + height: Default::default(), + // Use a p2pk output script for this UTXO + script: output_script_p2pk( + &coin + .as_ref() + .derivation_method + .unwrap_single_addr() + .await + .pubkey() + .unwrap(), + ), + }]; + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); // Create a dummy p2pkh address to withdraw the coins to. @@ -3411,7 +3418,7 @@ fn test_withdraw_p2pk_balance() { memo: None, ibc_source_channel: None, }; - let tx_details = coin.withdraw(withdraw_req).wait().unwrap(); + let tx_details = block_on_f01(coin.withdraw(withdraw_req)).unwrap(); let transaction: UtxoTx = deserialize(tx_details.tx.tx_hex().unwrap().as_slice()).unwrap(); // The change should be in a p2pkh script. @@ -3432,8 +3439,11 @@ fn test_utxo_standard_with_check_utxo_maturity_true() { UtxoStandardCoin::get_mature_unspent_ordered_list.mock_safe(|coin, _| { unsafe { GET_MATURE_UNSPENT_ORDERED_LIST_CALLED = true }; - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - MockResult::Return(Box::pin(futures::future::ok((MatureUnspentList::default(), cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + Ok((MatureUnspentList::default(), cache)) + }; + MockResult::Return(fut.boxed()) }); let conf = json!({"coin":"RICK","asset":"RICK","rpcport":25435,"txversion":4,"overwintered":1,"mm2":1,"protocol":{"type":"UTXO"}}); @@ -3451,7 +3461,7 @@ fn test_utxo_standard_with_check_utxo_maturity_true() { let address = Address::from_legacyaddress("R9o9xTocqr6CeEDGDH6mEYpwLoMz6jNjMW", &KMD_PREFIXES).unwrap(); // Don't use `block_on` here because it's used within a mock of [`GetUtxoListOps::get_mature_unspent_ordered_list`]. - coin.get_unspent_ordered_list(&address).compat().wait().unwrap(); + block_on_f01(coin.get_unspent_ordered_list(&address).compat()).unwrap(); assert!(unsafe { GET_MATURE_UNSPENT_ORDERED_LIST_CALLED }); } @@ -3464,9 +3474,11 @@ fn test_utxo_standard_without_check_utxo_maturity() { UtxoStandardCoin::get_all_unspent_ordered_list.mock_safe(|coin, _| { unsafe { GET_ALL_UNSPENT_ORDERED_LIST_CALLED = true }; - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = Vec::new(); - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + Ok((Vec::new(), cache)) + }; + MockResult::Return(fut.boxed()) }); UtxoStandardCoin::get_mature_unspent_ordered_list.mock_safe(|_, _| { @@ -3487,7 +3499,7 @@ fn test_utxo_standard_without_check_utxo_maturity() { let address = Address::from_legacyaddress("R9o9xTocqr6CeEDGDH6mEYpwLoMz6jNjMW", &KMD_PREFIXES).unwrap(); // Don't use `block_on` here because it's used within a mock of [`UtxoStandardCoin::get_all_unspent_ordered_list`]. - coin.get_unspent_ordered_list(&address).compat().wait().unwrap(); + block_on_f01(coin.get_unspent_ordered_list(&address).compat()).unwrap(); assert!(unsafe { GET_ALL_UNSPENT_ORDERED_LIST_CALLED }); } @@ -3500,8 +3512,11 @@ fn test_qtum_without_check_utxo_maturity() { QtumCoin::get_mature_unspent_ordered_list.mock_safe(|coin, _| { unsafe { GET_MATURE_UNSPENT_ORDERED_LIST_CALLED = true }; - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - MockResult::Return(Box::pin(futures::future::ok((MatureUnspentList::default(), cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + Ok((MatureUnspentList::default(), cache)) + }; + MockResult::Return(fut.boxed()) }); let conf = json!({"coin":"tQTUM","rpcport":13889,"pubtype":120,"p2shtype":110}); @@ -3526,7 +3541,7 @@ fn test_qtum_without_check_utxo_maturity() { ) .unwrap(); // Don't use `block_on` here because it's used within a mock of [`QtumCoin::get_mature_unspent_ordered_list`]. - coin.get_unspent_ordered_list(&address).compat().wait().unwrap(); + block_on_f01(coin.get_unspent_ordered_list(&address).compat()).unwrap(); assert!(unsafe { GET_MATURE_UNSPENT_ORDERED_LIST_CALLED }); } @@ -3604,9 +3619,12 @@ fn test_qtum_with_check_utxo_maturity_false() { QtumCoin::get_all_unspent_ordered_list.mock_safe(|coin, _address| { unsafe { GET_ALL_UNSPENT_ORDERED_LIST_CALLED = true }; - let cache = block_on(coin.as_ref().recently_spent_outpoints.lock()); - let unspents = Vec::new(); - MockResult::Return(Box::pin(futures::future::ok((unspents, cache)))) + let fut = async move { + let cache = coin.as_ref().recently_spent_outpoints.lock().await; + let unspents = Vec::new(); + Ok((unspents, cache)) + }; + MockResult::Return(fut.boxed()) }); QtumCoin::get_mature_unspent_ordered_list.mock_safe(|_, _| { panic!( @@ -3637,7 +3655,7 @@ fn test_qtum_with_check_utxo_maturity_false() { ) .unwrap(); // Don't use `block_on` here because it's used within a mock of [`QtumCoin::get_all_unspent_ordered_list`]. - coin.get_unspent_ordered_list(&address).compat().wait().unwrap(); + block_on_f01(coin.get_unspent_ordered_list(&address).compat()).unwrap(); assert!(unsafe { GET_ALL_UNSPENT_ORDERED_LIST_CALLED }); } @@ -4365,7 +4383,9 @@ fn test_for_non_existent_tx_hex_utxo_electrum() { wait_until: timeout, check_every: 1, }; - let actual = coin.wait_for_confirmations(confirm_payment_input).wait().err().unwrap(); + let actual = block_on_f01(coin.wait_for_confirmations(confirm_payment_input)) + .err() + .unwrap(); assert!(actual.contains( "Tx d342ff9da528a2e262bddf2b6f9a27d1beb7aeb03f0fc8d9eac2987266447e44 was not found on chain after 10 tries" )); @@ -4408,10 +4428,7 @@ fn test_native_display_balances() { Address::from_legacyaddress("RJeDDtDRtKUoL8BCKdH7TNCHqUKr7kQRsi", &KMD_PREFIXES).unwrap(), Address::from_legacyaddress("RQHn9VPHBqNjYwyKfJbZCiaxVrWPKGQjeF", &KMD_PREFIXES).unwrap(), ]; - let actual = rpc_client - .display_balances(addresses, TEST_COIN_DECIMALS) - .wait() - .unwrap(); + let actual = block_on_f01(rpc_client.display_balances(addresses, TEST_COIN_DECIMALS)).unwrap(); let expected: Vec<(Address, BigDecimal)> = vec![ ( @@ -4549,7 +4566,6 @@ fn test_utxo_validate_valid_and_invalid_pubkey() { #[test] fn test_block_header_utxo_loop() { use crate::utxo::utxo_builder::{block_header_utxo_loop, BlockHeaderUtxoLoopExtraArgs}; - use futures::future::{Either, FutureExt}; use keys::hash::H256 as H256Json; static mut CURRENT_BLOCK_COUNT: u64 = 13; diff --git a/mm2src/coins/z_coin/z_coin_native_tests.rs b/mm2src/coins/z_coin/z_coin_native_tests.rs index 9e4358727d..790f42818f 100644 --- a/mm2src/coins/z_coin/z_coin_native_tests.rs +++ b/mm2src/coins/z_coin/z_coin_native_tests.rs @@ -1,14 +1,13 @@ use bitcrypto::dhash160; -use common::{block_on, now_sec}; +use common::{block_on, block_on_f01, now_sec}; use mm2_core::mm_ctx::MmCtxBuilder; use mm2_test_helpers::for_tests::zombie_conf; use std::path::PathBuf; use std::time::Duration; use zcash_client_backend::encoding::decode_extended_spending_key; -use super::{z_coin_from_conf_and_params_with_z_key, z_mainnet_constants, Future, PrivKeyBuildPolicy, - RefundPaymentArgs, SendPaymentArgs, SpendPaymentArgs, SwapOps, ValidateFeeArgs, ValidatePaymentError, - ZTransaction}; +use super::{z_coin_from_conf_and_params_with_z_key, z_mainnet_constants, PrivKeyBuildPolicy, RefundPaymentArgs, + SendPaymentArgs, SpendPaymentArgs, SwapOps, ValidateFeeArgs, ValidatePaymentError, ZTransaction}; use crate::z_coin::{z_htlc::z_send_dex_fee, ZcoinActivationParams, ZcoinRpcMode}; use crate::DexFee; use crate::{CoinProtocol, SwapTxTypeWithSecretHash}; @@ -55,7 +54,7 @@ fn zombie_coin_send_and_refund_maker_payment() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_maker_payment(args).wait().unwrap(); + let tx = block_on_f01(coin.send_maker_payment(args)).unwrap(); log!("swap tx {}", hex::encode(tx.tx_hash_as_bytes().0)); let refund_args = RefundPaymentArgs { @@ -116,7 +115,7 @@ fn zombie_coin_send_and_spend_maker_payment() { wait_for_confirmation_until: 0, }; - let tx = coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let tx = block_on_f01(coin.send_maker_payment(maker_payment_args)).unwrap(); log!("swap tx {}", hex::encode(tx.tx_hash_as_bytes().0)); let maker_pub = taker_pub; @@ -234,7 +233,9 @@ fn zombie_coin_validate_dex_fee() { uuid: &[1; 16], }; // Invalid amount should return an error - let err = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let err = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); match err { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("Dex fee has invalid amount")), _ => panic!("Expected `WrongPaymentTx`: {:?}", err), @@ -249,7 +250,9 @@ fn zombie_coin_validate_dex_fee() { min_block_number: 12000, uuid: &[2; 16], }; - let err = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let err = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); match err { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("Dex fee has invalid memo")), _ => panic!("Expected `WrongPaymentTx`: {:?}", err), @@ -264,7 +267,9 @@ fn zombie_coin_validate_dex_fee() { min_block_number: 14000, uuid: &[1; 16], }; - let err = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + let err = block_on_f01(coin.validate_fee(validate_fee_args)) + .unwrap_err() + .into_inner(); match err { ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("confirmed before min block")), _ => panic!("Expected `WrongPaymentTx`: {:?}", err), @@ -279,7 +284,7 @@ fn zombie_coin_validate_dex_fee() { min_block_number: 12000, uuid: &[1; 16], }; - coin.validate_fee(validate_fee_args).wait().unwrap(); + block_on_f01(coin.validate_fee(validate_fee_args)).unwrap(); } fn default_zcoin_activation_params() -> ZcoinActivationParams { diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index 0eeb726ad4..f665a9a8e0 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -621,7 +621,20 @@ pub fn var(name: &str) -> Result { #[cfg(target_arch = "wasm32")] pub fn var(_name: &str) -> Result { ERR!("Environment variable not supported in WASM") } +/// Runs the given future on MM2's executor and waits for the result. +/// +/// This is compatible with futures 0.1. +pub fn block_on_f01(f: F) -> Result +where + F: Future, +{ + block_on(f.compat()) +} + #[cfg(not(target_arch = "wasm32"))] +/// Runs the given future on MM2's executor and waits for the result. +/// +/// This is compatible with futures 0.3. pub fn block_on(f: F) -> F::Output where F: Future03, diff --git a/mm2src/mm2_err_handle/src/map_to_mm_fut.rs b/mm2src/mm2_err_handle/src/map_to_mm_fut.rs index 01de1b7d7e..0cfeb9cf13 100644 --- a/mm2src/mm2_err_handle/src/map_to_mm_fut.rs +++ b/mm2src/mm2_err_handle/src/map_to_mm_fut.rs @@ -21,7 +21,7 @@ where /// /// ```rust /// let fut = futures01::future::err("An error".to_owned()); - /// let mapped_res: Result<(), MmError> = fut.map_to_mm_fut(|e| e.len()).wait(); + /// let mapped_res: Result<(), MmError> = block_on_f01(fut.map_to_mm_fut(|e| e.len())); /// ``` #[track_caller] fn map_to_mm_fut(self, f: F) -> MapToMmFuture<'a, T, E1, E2> diff --git a/mm2src/mm2_err_handle/src/mm_error.rs b/mm2src/mm2_err_handle/src/mm_error.rs index 56e7f29f50..1ea7bf1555 100644 --- a/mm2src/mm2_err_handle/src/mm_error.rs +++ b/mm2src/mm2_err_handle/src/mm_error.rs @@ -332,6 +332,7 @@ impl FormattedTrace for Vec { mod tests { use super::*; use crate::prelude::*; + use common::block_on_f01; use futures01::Future; use ser_error_derive::SerializeErrorType; use serde_json::{self as json, json}; @@ -425,10 +426,8 @@ mod tests { } let into_mm_line = line!() + 2; - let mm_err = generate_error("An error") - .map_to_mm_fut(|error| error.len()) - .wait() - .expect_err("Expected an error"); + let mm_err = + block_on_f01(generate_error("An error").map_to_mm_fut(|error| error.len())).expect_err("Expected an error"); assert_eq!(mm_err.etype, 8); assert_eq!(mm_err.trace, vec![TraceLocation::new("mm_error", into_mm_line)]); } diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index fe5d7f96d4..49150fab55 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -1,4 +1,4 @@ -pub use common::{block_on, now_ms, now_sec, wait_until_ms, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY}; +pub use common::{block_on, block_on_f01, now_ms, now_sec, wait_until_ms, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY}; pub use mm2_number::MmNumber; use mm2_rpc::data::legacy::BalanceResponse; pub use mm2_test_helpers::for_tests::{check_my_swap_status, check_recent_swaps, enable_eth_coin, enable_native, @@ -27,7 +27,6 @@ use crypto::Secp256k1Secret; use ethabi::Token; use ethereum_types::{H160 as H160Eth, U256}; use futures::TryFutureExt; -use futures01::Future; use http::StatusCode; use keys::{Address, AddressBuilder, AddressHashEnum, AddressPrefix, KeyPair, NetworkAddressPrefixes, NetworkPrefix as CashAddrPrefix}; @@ -155,13 +154,13 @@ pub trait CoinDockerOps { fn wait_ready(&self, expected_tx_version: i32) { let timeout = wait_until_ms(120000); loop { - match self.rpc_client().get_block_count().wait() { + match block_on_f01(self.rpc_client().get_block_count()) { Ok(n) => { if n > 1 { if let UtxoRpcClientEnum::Native(client) = self.rpc_client() { - let hash = client.get_block_hash(n).wait().unwrap(); - let block = client.get_block(hash).wait().unwrap(); - let coinbase = client.get_verbose_transaction(&block.tx[0]).wait().unwrap(); + let hash = block_on_f01(client.get_block_hash(n)).unwrap(); + let block = block_on_f01(client.get_block(hash)).unwrap(); + let coinbase = block_on_f01(client.get_verbose_transaction(&block.tx[0])).unwrap(); log!("Coinbase tx {:?} in block {}", coinbase, n); if coinbase.version == expected_tx_version { break; @@ -251,10 +250,11 @@ impl BchDockerOps { .build() .expect("valid address props"); - self.native_client() - .import_address(&address.to_string(), &address.to_string(), false) - .wait() - .unwrap(); + block_on_f01( + self.native_client() + .import_address(&address.to_string(), &address.to_string(), false), + ) + .unwrap(); let script_pubkey = Builder::build_p2pkh(&key_pair.public().address_hash().into()); @@ -270,9 +270,7 @@ impl BchDockerOps { slp_privkeys.push(*key_pair.private_ref()); } - let slp_genesis_tx = send_outputs_from_my_address(self.coin.clone(), bch_outputs) - .wait() - .unwrap(); + let slp_genesis_tx = block_on_f01(send_outputs_from_my_address(self.coin.clone(), bch_outputs)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: slp_genesis_tx.tx_hex(), confirmations: 1, @@ -280,7 +278,7 @@ impl BchDockerOps { wait_until: wait_until_sec(30), check_every: 1, }; - self.coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(self.coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let adex_slp = SlpToken::new( 8, @@ -299,7 +297,7 @@ impl BchDockerOps { wait_until: wait_until_sec(30), check_every: 1, }; - self.coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(self.coin.wait_for_confirmations(confirm_payment_input)).unwrap(); *SLP_TOKEN_OWNERS.lock().unwrap() = slp_privkeys; *SLP_TOKEN_ID.lock().unwrap() = slp_genesis_tx.tx_hash_as_bytes().as_slice().into(); } @@ -466,7 +464,7 @@ where match coin.as_ref().rpc_client { UtxoRpcClientEnum::Native(ref native) => { let my_address = coin.my_address().unwrap(); - native.import_address(&my_address, &my_address, false).wait().unwrap() + block_on_f01(native.import_address(&my_address, &my_address, false)).unwrap() }, UtxoRpcClientEnum::Electrum(_) => panic!("Expected NativeClient"), } @@ -586,9 +584,7 @@ where UtxoRpcClientEnum::Native(ref native) => native, UtxoRpcClientEnum::Electrum(_) => panic!("NativeClient expected"), }; - let mut addresses = native - .get_addresses_by_label(label) - .wait() + let mut addresses = block_on_f01(native.get_addresses_by_label(label)) .expect("!getaddressesbylabel") .into_iter(); match addresses.next() { @@ -610,22 +606,20 @@ pub fn fill_qrc20_address(coin: &Qrc20Coin, amount: BigDecimal, timeout: u64) { }; let from_addr = get_address_by_label(coin, QTUM_ADDRESS_LABEL); - let to_addr = coin.my_addr_as_contract_addr().compat().wait().unwrap(); + let to_addr = block_on_f01(coin.my_addr_as_contract_addr().compat()).unwrap(); let satoshis = sat_from_big_decimal(&amount, coin.as_ref().decimals).expect("!sat_from_big_decimal"); - let hash = client - .transfer_tokens( - &coin.contract_address, - &from_addr, - to_addr, - satoshis.into(), - coin.as_ref().decimals, - ) - .wait() - .expect("!transfer_tokens") - .txid; + let hash = block_on_f01(client.transfer_tokens( + &coin.contract_address, + &from_addr, + to_addr, + satoshis.into(), + coin.as_ref().decimals, + )) + .expect("!transfer_tokens") + .txid; - let tx_bytes = client.get_transaction_bytes(&hash).wait().unwrap(); + let tx_bytes = block_on_f01(client.get_transaction_bytes(&hash)).unwrap(); log!("{:02x}", tx_bytes); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx_bytes.0, @@ -634,7 +628,7 @@ pub fn fill_qrc20_address(coin: &Qrc20Coin, amount: BigDecimal, timeout: u64) { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); } /// Generate random privkey, create a QRC20 coin and fill it's address with the specified balance. @@ -742,9 +736,9 @@ where let timeout = wait_until_sec(timeout); if let UtxoRpcClientEnum::Native(client) = &coin.as_ref().rpc_client { - client.import_address(address, address, false).wait().unwrap(); - let hash = client.send_to_address(address, &amount).wait().unwrap(); - let tx_bytes = client.get_transaction_bytes(&hash).wait().unwrap(); + block_on_f01(client.import_address(address, address, false)).unwrap(); + let hash = block_on_f01(client.send_to_address(address, &amount)).unwrap(); + let tx_bytes = block_on_f01(client.get_transaction_bytes(&hash)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx_bytes.clone().0, confirmations: 1, @@ -752,13 +746,10 @@ where wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); log!("{:02x}", tx_bytes); loop { - let unspents = client - .list_unspent_impl(0, std::i32::MAX, vec![address.to_string()]) - .wait() - .unwrap(); + let unspents = block_on_f01(client.list_unspent_impl(0, std::i32::MAX, vec![address.to_string()])).unwrap(); if !unspents.is_empty() { break; } @@ -794,7 +785,7 @@ pub fn wait_for_estimate_smart_fee(timeout: u64) -> Result<(), String> { UtxoRpcClientEnum::Electrum(_) => panic!("Expected NativeClient"), }; while now_sec() < timeout { - if let Ok(res) = client.estimate_smart_fee(&None, 1).wait() { + if let Ok(res) = block_on_f01(client.estimate_smart_fee(&None, 1)) { if res.errors.is_empty() { *state = EstimateSmartFeeState::Ok; return Ok(()); diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs index 330dec30de..fd9e4eefb6 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs @@ -12,10 +12,9 @@ use coins::TxFeeDetails; use coins::{ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, MmCoin, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, TransactionEnum, WithdrawRequest}; -use common::{block_on, executor::Timer, get_utc_timestamp, now_sec, wait_until_sec}; +use common::{block_on, block_on_f01, executor::Timer, get_utc_timestamp, now_sec, wait_until_sec}; use crypto::privkey::key_pair_from_seed; use crypto::{CryptoCtx, DerivationPath, KeyPairPolicy}; -use futures01::Future; use http::StatusCode; use mm2_number::{BigDecimal, BigRational, MmNumber}; use mm2_test_helpers::for_tests::{check_my_swap_status_amounts, disable_coin, disable_coin_err, enable_eth_coin, @@ -51,7 +50,7 @@ fn test_search_for_swap_tx_spend_native_was_refunded_taker() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_taker_payment(taker_payment_args).wait().unwrap(); + let tx = block_on_f01(coin.send_taker_payment(taker_payment_args)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx.tx_hex(), @@ -60,7 +59,7 @@ fn test_search_for_swap_tx_spend_native_was_refunded_taker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let maker_refunds_payment_args = RefundPaymentArgs { payment_tx: &tx.tx_hex(), time_lock, @@ -81,7 +80,7 @@ fn test_search_for_swap_tx_spend_native_was_refunded_taker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -113,7 +112,9 @@ fn test_for_non_existent_tx_hex_utxo() { wait_until: timeout, check_every: 1, }; - let actual = coin.wait_for_confirmations(confirm_payment_input).wait().err().unwrap(); + let actual = block_on_f01(coin.wait_for_confirmations(confirm_payment_input)) + .err() + .unwrap(); assert!(actual.contains( "Tx d342ff9da528a2e262bddf2b6f9a27d1beb7aeb03f0fc8d9eac2987266447e44 was not found on chain after 10 tries" )); @@ -138,7 +139,7 @@ fn test_search_for_swap_tx_spend_native_was_refunded_maker() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let tx = block_on_f01(coin.send_maker_payment(maker_payment_args)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx.tx_hex(), @@ -147,7 +148,7 @@ fn test_search_for_swap_tx_spend_native_was_refunded_maker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let maker_refunds_payment_args = RefundPaymentArgs { payment_tx: &tx.tx_hex(), time_lock, @@ -168,7 +169,7 @@ fn test_search_for_swap_tx_spend_native_was_refunded_maker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -207,7 +208,7 @@ fn test_search_for_taker_swap_tx_spend_native_was_spent_by_maker() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_taker_payment(taker_payment_args).wait().unwrap(); + let tx = block_on_f01(coin.send_taker_payment(taker_payment_args)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx.tx_hex(), @@ -216,7 +217,7 @@ fn test_search_for_taker_swap_tx_spend_native_was_spent_by_maker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let maker_spends_payment_args = SpendPaymentArgs { other_payment_tx: &tx.tx_hex(), time_lock, @@ -236,7 +237,7 @@ fn test_search_for_taker_swap_tx_spend_native_was_spent_by_maker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -275,7 +276,7 @@ fn test_search_for_maker_swap_tx_spend_native_was_spent_by_taker() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let tx = block_on_f01(coin.send_maker_payment(maker_payment_args)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx.tx_hex(), @@ -284,7 +285,7 @@ fn test_search_for_maker_swap_tx_spend_native_was_spent_by_taker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let taker_spends_payment_args = SpendPaymentArgs { other_payment_tx: &tx.tx_hex(), time_lock, @@ -304,7 +305,7 @@ fn test_search_for_maker_swap_tx_spend_native_was_spent_by_taker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -346,7 +347,7 @@ fn test_one_hundred_maker_payments_in_a_row_native() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let tx = block_on_f01(coin.send_maker_payment(maker_payment_args)).unwrap(); if let TransactionEnum::UtxoTx(tx) = tx { unspents.push(UnspentInfo { outpoint: OutPoint { @@ -2472,16 +2473,12 @@ fn test_maker_order_should_not_kick_start_and_appear_in_orderbook_if_balance_is_ bob_conf["log"] = mm_bob.folder.join("mm2_dup.log").to_str().unwrap().into(); block_on(mm_bob.stop()).unwrap(); - let withdraw = coin - .withdraw(WithdrawRequest::new_max( - "MYCOIN".to_string(), - "RRYmiZSDo3UdHHqj1rLKf8cbJroyv9NxXw".to_string(), - )) - .wait() - .unwrap(); - coin.send_raw_tx(&hex::encode(&withdraw.tx.tx_hex().unwrap().0)) - .wait() - .unwrap(); + let withdraw = block_on_f01(coin.withdraw(WithdrawRequest::new_max( + "MYCOIN".to_string(), + "RRYmiZSDo3UdHHqj1rLKf8cbJroyv9NxXw".to_string(), + ))) + .unwrap(); + block_on_f01(coin.send_raw_tx(&hex::encode(&withdraw.tx.tx_hex().unwrap().0))).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: withdraw.tx.tx_hex().unwrap().0.to_owned(), confirmations: 1, @@ -2489,7 +2486,7 @@ fn test_maker_order_should_not_kick_start_and_appear_in_orderbook_if_balance_is_ wait_until: wait_until_sec(10), check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let mm_bob_dup = MarketMakerIt::start(bob_conf, "pass".to_string(), None).unwrap(); let (_bob_dup_dump_log, _bob_dup_dump_dashboard) = mm_dump(&mm_bob_dup.log_path); diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 3a898b0f2f..cc44cb5af1 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -19,10 +19,9 @@ use coins::{lp_coinfind, CoinProtocol, CoinWithDerivationMethod, CoinsContext, C SendNftMakerPaymentArgs, SendPaymentArgs, SendTakerFundingArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, Transaction, TxPreimageWithSig, ValidateNftMakerPaymentArgs, ValidateTakerFundingArgs}; -use common::{block_on, now_sec}; +use common::{block_on, block_on_f01, now_sec}; use crypto::Secp256k1Secret; use ethereum_types::U256; -use futures01::Future; use mm2_core::mm_ctx::MmArc; use mm2_number::{BigDecimal, BigUint}; use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, eth_sepolia_conf, nft_dev_conf, sepolia_erc20_dev_conf}; @@ -540,7 +539,7 @@ fn send_and_refund_eth_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { watcher_reward: None, wait_for_confirmation_until: 0, }; - let eth_maker_payment = eth_coin.send_maker_payment(send_payment_args).wait().unwrap(); + let eth_maker_payment = block_on_f01(eth_coin.send_maker_payment(send_payment_args)).unwrap(); let confirm_input = ConfirmPaymentInput { payment_tx: eth_maker_payment.tx_hex(), @@ -549,7 +548,7 @@ fn send_and_refund_eth_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { wait_until: now_sec() + 60, check_every: 1, }; - eth_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(eth_coin.wait_for_confirmations(confirm_input)).unwrap(); let refund_args = RefundPaymentArgs { payment_tx: ð_maker_payment.tx_hex(), @@ -572,7 +571,7 @@ fn send_and_refund_eth_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { wait_until: now_sec() + 60, check_every: 1, }; - eth_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(eth_coin.wait_for_confirmations(confirm_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -626,7 +625,7 @@ fn send_and_spend_eth_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { watcher_reward: None, wait_for_confirmation_until: 0, }; - let eth_maker_payment = maker_eth_coin.send_maker_payment(send_payment_args).wait().unwrap(); + let eth_maker_payment = block_on_f01(maker_eth_coin.send_maker_payment(send_payment_args)).unwrap(); let confirm_input = ConfirmPaymentInput { payment_tx: eth_maker_payment.tx_hex(), @@ -635,7 +634,7 @@ fn send_and_spend_eth_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { wait_until: now_sec() + 60, check_every: 1, }; - taker_eth_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(taker_eth_coin.wait_for_confirmations(confirm_input)).unwrap(); let spend_args = SpendPaymentArgs { other_payment_tx: ð_maker_payment.tx_hex(), @@ -657,7 +656,7 @@ fn send_and_spend_eth_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { wait_until: now_sec() + 60, check_every: 1, }; - taker_eth_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(taker_eth_coin.wait_for_confirmations(confirm_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -709,7 +708,7 @@ fn send_and_refund_erc20_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) watcher_reward: None, wait_for_confirmation_until: now_sec() + 60, }; - let eth_maker_payment = erc20_coin.send_maker_payment(send_payment_args).wait().unwrap(); + let eth_maker_payment = block_on_f01(erc20_coin.send_maker_payment(send_payment_args)).unwrap(); let confirm_input = ConfirmPaymentInput { payment_tx: eth_maker_payment.tx_hex(), @@ -718,7 +717,7 @@ fn send_and_refund_erc20_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) wait_until: now_sec() + 60, check_every: 1, }; - erc20_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(erc20_coin.wait_for_confirmations(confirm_input)).unwrap(); let refund_args = RefundPaymentArgs { payment_tx: ð_maker_payment.tx_hex(), @@ -741,7 +740,7 @@ fn send_and_refund_erc20_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) wait_until: now_sec() + 60, check_every: 1, }; - erc20_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(erc20_coin.wait_for_confirmations(confirm_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -798,7 +797,7 @@ fn send_and_spend_erc20_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { watcher_reward: None, wait_for_confirmation_until: now_sec() + 60, }; - let eth_maker_payment = maker_erc20_coin.send_maker_payment(send_payment_args).wait().unwrap(); + let eth_maker_payment = block_on_f01(maker_erc20_coin.send_maker_payment(send_payment_args)).unwrap(); let confirm_input = ConfirmPaymentInput { payment_tx: eth_maker_payment.tx_hex(), @@ -807,7 +806,7 @@ fn send_and_spend_erc20_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { wait_until: now_sec() + 60, check_every: 1, }; - taker_erc20_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(taker_erc20_coin.wait_for_confirmations(confirm_input)).unwrap(); let spend_args = SpendPaymentArgs { other_payment_tx: ð_maker_payment.tx_hex(), @@ -829,7 +828,7 @@ fn send_and_spend_erc20_maker_payment_impl(swap_txfee_policy: SwapTxFeePolicy) { wait_until: now_sec() + 60, check_every: 1, }; - taker_erc20_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(taker_erc20_coin.wait_for_confirmations(confirm_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -971,12 +970,12 @@ fn test_nonce_several_urls() { // Use one working and one failing URL. let coin = eth_coin_with_random_privkey_using_urls(swap_contract(), &[GETH_RPC_URL, "http://127.0.0.1:0"]); let my_address = block_on(coin.derivation_method().single_addr_or_err()).unwrap(); - let (old_nonce, _) = coin.clone().get_addr_nonce(my_address).wait().unwrap(); + let (old_nonce, _) = block_on_f01(coin.clone().get_addr_nonce(my_address)).unwrap(); // Send a payment to increase the nonce. - coin.send_to_address(my_address, 200000000.into()).wait().unwrap(); + block_on_f01(coin.send_to_address(my_address, 200000000.into())).unwrap(); - let (new_nonce, _) = coin.get_addr_nonce(my_address).wait().unwrap(); + let (new_nonce, _) = block_on_f01(coin.get_addr_nonce(my_address)).unwrap(); assert_eq!(old_nonce + 1, new_nonce); } @@ -1308,7 +1307,7 @@ fn wait_for_confirmations(coin: &EthCoin, tx: &SignedEthTx, wait_seconds: u64) { wait_until: now_sec() + wait_seconds, check_every: 1, }; - coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_input)).unwrap(); } fn validate_nft_maker_payment(setup: &NftTestSetup, maker_payment: &SignedEthTx, amount: BigDecimal) { diff --git a/mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs b/mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs index e66a3a5852..6d8d03d96c 100644 --- a/mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs @@ -11,10 +11,9 @@ use coins::{CheckIfMyPaymentSentArgs, ConfirmPaymentInput, DexFee, FeeApproxStag SwapTxTypeWithSecretHash, TradePreimageValue, TransactionEnum, ValidateFeeArgs, ValidatePaymentInput, WaitForHTLCTxSpendArgs}; use common::log::debug; -use common::{temp_dir, DEX_FEE_ADDR_RAW_PUBKEY}; +use common::{block_on_f01, temp_dir, DEX_FEE_ADDR_RAW_PUBKEY}; use crypto::Secp256k1Secret; use ethereum_types::H160; -use futures01::Future; use http::StatusCode; use mm2_core::mm_ctx::{MmArc, MmCtxBuilder}; use mm2_main::lp_swap::{dex_fee_amount, max_taker_vol_from_available}; @@ -78,9 +77,7 @@ impl QtumDockerOps { match self.coin.as_ref().rpc_client { UtxoRpcClientEnum::Native(ref native) => { - let result = native - .create_contract(&bytecode.into(), gas_limit, gas_price, sender) - .wait() + let result = block_on_f01(native.create_contract(&bytecode.into(), gas_limit, gas_price, sender)) .expect("!createcontract"); result.address.0.into() }, @@ -165,14 +162,8 @@ fn withdraw_and_send(mm: &MarketMakerIt, coin: &str, to: &str, amount: f64) { fn test_taker_spends_maker_payment() { let (_ctx, maker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); let (_ctx, taker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 1.into()); - let maker_old_balance = maker_coin - .my_spendable_balance() - .wait() - .expect("Error on get maker balance"); - let taker_old_balance = taker_coin - .my_spendable_balance() - .wait() - .expect("Error on get taker balance"); + let maker_old_balance = block_on_f01(maker_coin.my_spendable_balance()).expect("Error on get maker balance"); + let taker_old_balance = block_on_f01(taker_coin.my_spendable_balance()).expect("Error on get taker balance"); assert_eq!(maker_old_balance, BigDecimal::from(10)); assert_eq!(taker_old_balance, BigDecimal::from(1)); @@ -194,7 +185,7 @@ fn test_taker_spends_maker_payment() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = maker_coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let payment = block_on_f01(maker_coin.send_maker_payment(maker_payment_args)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Maker payment: {:?}", payment_tx_hash); @@ -210,7 +201,7 @@ fn test_taker_spends_maker_payment() { wait_until, check_every, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let input = ValidatePaymentInput { payment_tx: payment_tx_hex.clone(), @@ -249,16 +240,10 @@ fn test_taker_spends_maker_payment() { wait_until, check_every, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); - - let maker_balance = maker_coin - .my_spendable_balance() - .wait() - .expect("Error on get maker balance"); - let taker_balance = taker_coin - .my_spendable_balance() - .wait() - .expect("Error on get taker balance"); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); + + let maker_balance = block_on_f01(maker_coin.my_spendable_balance()).expect("Error on get maker balance"); + let taker_balance = block_on_f01(taker_coin.my_spendable_balance()).expect("Error on get taker balance"); assert_eq!(maker_old_balance - amount.clone(), maker_balance); assert_eq!(taker_old_balance + amount, taker_balance); } @@ -267,14 +252,8 @@ fn test_taker_spends_maker_payment() { fn test_maker_spends_taker_payment() { let (_ctx, maker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); let (_ctx, taker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); - let maker_old_balance = maker_coin - .my_spendable_balance() - .wait() - .expect("Error on get maker balance"); - let taker_old_balance = taker_coin - .my_spendable_balance() - .wait() - .expect("Error on get taker balance"); + let maker_old_balance = block_on_f01(maker_coin.my_spendable_balance()).expect("Error on get maker balance"); + let taker_old_balance = block_on_f01(taker_coin.my_spendable_balance()).expect("Error on get taker balance"); assert_eq!(maker_old_balance, BigDecimal::from(10)); assert_eq!(taker_old_balance, BigDecimal::from(10)); @@ -296,7 +275,7 @@ fn test_maker_spends_taker_payment() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = taker_coin.send_taker_payment(taker_payment_args).wait().unwrap(); + let payment = block_on_f01(taker_coin.send_taker_payment(taker_payment_args)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Taker payment: {:?}", payment_tx_hash); @@ -312,7 +291,7 @@ fn test_maker_spends_taker_payment() { wait_until, check_every, }; - maker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let input = ValidatePaymentInput { payment_tx: payment_tx_hex.clone(), @@ -351,16 +330,10 @@ fn test_maker_spends_taker_payment() { wait_until, check_every, }; - maker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); - - let maker_balance = maker_coin - .my_spendable_balance() - .wait() - .expect("Error on get maker balance"); - let taker_balance = taker_coin - .my_spendable_balance() - .wait() - .expect("Error on get taker balance"); + block_on_f01(maker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); + + let maker_balance = block_on_f01(maker_coin.my_spendable_balance()).expect("Error on get maker balance"); + let taker_balance = block_on_f01(taker_coin.my_spendable_balance()).expect("Error on get taker balance"); assert_eq!(maker_old_balance + amount.clone(), maker_balance); assert_eq!(taker_old_balance - amount, taker_balance); } @@ -368,7 +341,7 @@ fn test_maker_spends_taker_payment() { #[test] fn test_maker_refunds_payment() { let (_ctx, coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); - let expected_balance = coin.my_spendable_balance().wait().unwrap(); + let expected_balance = block_on_f01(coin.my_spendable_balance()).unwrap(); assert_eq!(expected_balance, BigDecimal::from(10)); let timelock = now_sec() - 200; @@ -387,7 +360,7 @@ fn test_maker_refunds_payment() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = coin.send_maker_payment(maker_payment).wait().unwrap(); + let payment = block_on_f01(coin.send_maker_payment(maker_payment)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Maker payment: {:?}", payment_tx_hash); @@ -403,9 +376,9 @@ fn test_maker_refunds_payment() { wait_until, check_every, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let balance_after_payment = coin.my_spendable_balance().wait().unwrap(); + let balance_after_payment = block_on_f01(coin.my_spendable_balance()).unwrap(); assert_eq!(expected_balance.clone() - amount, balance_after_payment); let maker_refunds_payment_args = RefundPaymentArgs { payment_tx: &payment_tx_hex, @@ -431,16 +404,16 @@ fn test_maker_refunds_payment() { wait_until, check_every, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let balance_after_refund = coin.my_spendable_balance().wait().unwrap(); + let balance_after_refund = block_on_f01(coin.my_spendable_balance()).unwrap(); assert_eq!(expected_balance, balance_after_refund); } #[test] fn test_taker_refunds_payment() { let (_ctx, coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); - let expected_balance = coin.my_spendable_balance().wait().unwrap(); + let expected_balance = block_on_f01(coin.my_spendable_balance()).unwrap(); assert_eq!(expected_balance, BigDecimal::from(10)); let timelock = now_sec() - 200; @@ -459,7 +432,7 @@ fn test_taker_refunds_payment() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = coin.send_taker_payment(taker_payment_args).wait().unwrap(); + let payment = block_on_f01(coin.send_taker_payment(taker_payment_args)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Taker payment: {:?}", payment_tx_hash); @@ -475,9 +448,9 @@ fn test_taker_refunds_payment() { wait_until, check_every, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let balance_after_payment = coin.my_spendable_balance().wait().unwrap(); + let balance_after_payment = block_on_f01(coin.my_spendable_balance()).unwrap(); assert_eq!(expected_balance.clone() - amount, balance_after_payment); let taker_refunds_payment_args = RefundPaymentArgs { payment_tx: &payment_tx_hex, @@ -503,9 +476,9 @@ fn test_taker_refunds_payment() { wait_until, check_every, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let balance_after_refund = coin.my_spendable_balance().wait().unwrap(); + let balance_after_refund = block_on_f01(coin.my_spendable_balance()).unwrap(); assert_eq!(expected_balance, balance_after_refund); } @@ -528,7 +501,7 @@ fn test_check_if_my_payment_sent() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let payment = block_on_f01(coin.send_maker_payment(maker_payment_args)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Maker payment: {:?}", payment_tx_hash); @@ -544,9 +517,9 @@ fn test_check_if_my_payment_sent() { wait_until, check_every, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let search_from_block = coin.current_block().wait().expect("!current_block") - 10; + let search_from_block = block_on_f01(coin.current_block()).expect("!current_block") - 10; let if_my_payment_sent_args = CheckIfMyPaymentSentArgs { time_lock: timelock, other_pub: &taker_pub, @@ -557,7 +530,7 @@ fn test_check_if_my_payment_sent() { amount: &amount, payment_instructions: &None, }; - let found = coin.check_if_my_payment_sent(if_my_payment_sent_args).wait().unwrap(); + let found = block_on_f01(coin.check_if_my_payment_sent(if_my_payment_sent_args)).unwrap(); assert_eq!(found, Some(payment)); } @@ -565,7 +538,7 @@ fn test_check_if_my_payment_sent() { fn test_search_for_swap_tx_spend_taker_spent() { let (_ctx, maker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); let (_ctx, taker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 1.into()); - let search_from_block = maker_coin.current_block().wait().expect("!current_block"); + let search_from_block = block_on_f01(maker_coin.current_block()).expect("!current_block"); let timelock = now_sec() - 200; let maker_pub = maker_coin.my_public_key().unwrap(); @@ -585,7 +558,7 @@ fn test_search_for_swap_tx_spend_taker_spent() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = maker_coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let payment = block_on_f01(maker_coin.send_maker_payment(maker_payment_args)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Maker payment: {:?}", payment_tx_hash); @@ -601,7 +574,7 @@ fn test_search_for_swap_tx_spend_taker_spent() { wait_until, check_every, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let taker_spends_payment_args = SpendPaymentArgs { other_payment_tx: &payment_tx_hex, time_lock: timelock, @@ -625,7 +598,7 @@ fn test_search_for_swap_tx_spend_taker_spent() { wait_until, check_every, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock: timelock, @@ -645,7 +618,7 @@ fn test_search_for_swap_tx_spend_taker_spent() { #[test] fn test_search_for_swap_tx_spend_maker_refunded() { let (_ctx, maker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); - let search_from_block = maker_coin.current_block().wait().expect("!current_block"); + let search_from_block = block_on_f01(maker_coin.current_block()).expect("!current_block"); let timelock = now_sec() - 200; let taker_pub = hex::decode("022b00078841f37b5d30a6a1defb82b3af4d4e2d24dd4204d41f0c9ce1e875de1a").unwrap(); @@ -664,7 +637,7 @@ fn test_search_for_swap_tx_spend_maker_refunded() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = maker_coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let payment = block_on_f01(maker_coin.send_maker_payment(maker_payment_args)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Maker payment: {:?}", payment_tx_hash); @@ -680,7 +653,7 @@ fn test_search_for_swap_tx_spend_maker_refunded() { wait_until, check_every, }; - maker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let maker_refunds_payment_args = RefundPaymentArgs { payment_tx: &payment_tx_hex, time_lock: timelock, @@ -705,7 +678,7 @@ fn test_search_for_swap_tx_spend_maker_refunded() { wait_until, check_every, }; - maker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock: timelock, @@ -725,7 +698,7 @@ fn test_search_for_swap_tx_spend_maker_refunded() { #[test] fn test_search_for_swap_tx_spend_not_spent() { let (_ctx, maker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); - let search_from_block = maker_coin.current_block().wait().expect("!current_block"); + let search_from_block = block_on_f01(maker_coin.current_block()).expect("!current_block"); let timelock = now_sec() - 200; let taker_pub = hex::decode("022b00078841f37b5d30a6a1defb82b3af4d4e2d24dd4204d41f0c9ce1e875de1a").unwrap(); @@ -744,7 +717,7 @@ fn test_search_for_swap_tx_spend_not_spent() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = maker_coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let payment = block_on_f01(maker_coin.send_maker_payment(maker_payment_args)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Maker payment: {:?}", payment_tx_hash); @@ -760,7 +733,7 @@ fn test_search_for_swap_tx_spend_not_spent() { wait_until, check_every, }; - maker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock: timelock, @@ -781,7 +754,7 @@ fn test_search_for_swap_tx_spend_not_spent() { fn test_wait_for_tx_spend() { let (_ctx, maker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 10.into()); let (_ctx, taker_coin, _priv_key) = generate_qrc20_coin_with_random_privkey("QICK", 20.into(), 1.into()); - let from_block = maker_coin.current_block().wait().expect("!current_block"); + let from_block = block_on_f01(maker_coin.current_block()).expect("!current_block"); let timelock = now_sec() - 200; let maker_pub = maker_coin.my_public_key().unwrap(); @@ -801,7 +774,7 @@ fn test_wait_for_tx_spend() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let payment = maker_coin.send_maker_payment(maker_payment_args).wait().unwrap(); + let payment = block_on_f01(maker_coin.send_maker_payment(maker_payment_args)).unwrap(); let payment_tx_hash = payment.tx_hash_as_bytes(); let payment_tx_hex = payment.tx_hex(); log!("Maker payment: {:?}", payment_tx_hash); @@ -817,22 +790,20 @@ fn test_wait_for_tx_spend() { wait_until, check_every, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); // first try to check if the wait_for_htlc_tx_spend() returns an error correctly let wait_until = wait_until_sec(5); - let tx_err = maker_coin - .wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { - tx_bytes: &payment_tx_hex, - secret_hash: &[], - wait_until, - from_block, - swap_contract_address: &maker_coin.swap_contract_address(), - check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, - watcher_reward: false, - }) - .wait() - .expect_err("Expected 'Waited too long' error"); + let tx_err = block_on_f01(maker_coin.wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { + tx_bytes: &payment_tx_hex, + secret_hash: &[], + wait_until, + from_block, + swap_contract_address: &maker_coin.swap_contract_address(), + check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, + watcher_reward: false, + })) + .expect_err("Expected 'Waited too long' error"); let err = tx_err.get_plain_text_format(); log!("error: {:?}", err); @@ -860,18 +831,16 @@ fn test_wait_for_tx_spend() { }); let wait_until = wait_until_sec(120); - let found = maker_coin - .wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { - tx_bytes: &payment_tx_hex, - secret_hash: &[], - wait_until, - from_block, - swap_contract_address: &maker_coin.swap_contract_address(), - check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, - watcher_reward: false, - }) - .wait() - .unwrap(); + let found = block_on_f01(maker_coin.wait_for_htlc_tx_spend(WaitForHTLCTxSpendArgs { + tx_bytes: &payment_tx_hex, + secret_hash: &[], + wait_until, + from_block, + swap_contract_address: &maker_coin.swap_contract_address(), + check_every: TAKER_PAYMENT_SPEND_SEARCH_INTERVAL, + watcher_reward: false, + })) + .unwrap(); unsafe { assert_eq!(Some(found), SPEND_TX) } } @@ -1030,7 +999,7 @@ fn test_get_max_taker_vol_and_trade_with_dynamic_trade_fee(coin: QtumCoin, priv_ log!("{:?}", block_on(enable_native(&mm, "MYCOIN", &[], None))); log!("{:?}", block_on(enable_native(&mm, "QTUM", &[], None))); - let qtum_balance = coin.my_spendable_balance().wait().expect("!my_balance"); + let qtum_balance = block_on_f01(coin.my_spendable_balance()).expect("!my_balance"); let qtum_min_tx_amount = MmNumber::from("0.000728"); // - `max_possible = balance - locked_amount`, where `locked_amount = 0` @@ -1103,10 +1072,8 @@ fn test_get_max_taker_vol_and_trade_with_dynamic_trade_fee(coin: QtumCoin, priv_ let secret_hash = &[0; 20]; let dex_fee = dex_fee_amount("QTUM", "MYCOIN", &expected_max_taker_vol, &qtum_min_tx_amount); - let _taker_fee_tx = coin - .send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, dex_fee, &[], timelock) - .wait() - .expect("!send_taker_fee"); + let _taker_fee_tx = + block_on_f01(coin.send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, dex_fee, &[], timelock)).expect("!send_taker_fee"); let taker_payment_args = SendPaymentArgs { time_lock_duration: 0, time_lock: timelock, @@ -1120,12 +1087,9 @@ fn test_get_max_taker_vol_and_trade_with_dynamic_trade_fee(coin: QtumCoin, priv_ wait_for_confirmation_until: 0, }; - let _taker_payment_tx = coin - .send_taker_payment(taker_payment_args) - .wait() - .expect("!send_taker_payment"); + let _taker_payment_tx = block_on_f01(coin.send_taker_payment(taker_payment_args)).expect("!send_taker_payment"); - let my_balance = coin.my_spendable_balance().wait().expect("!my_balance"); + let my_balance = block_on_f01(coin.my_spendable_balance()).expect("!my_balance"); assert_eq!( my_balance, BigDecimal::from(0u32), @@ -1519,7 +1483,7 @@ fn test_search_for_segwit_swap_tx_spend_native_was_refunded_maker() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_maker_payment(maker_payment).wait().unwrap(); + let tx = block_on_f01(coin.send_maker_payment(maker_payment)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx.tx_hex(), @@ -1528,7 +1492,7 @@ fn test_search_for_segwit_swap_tx_spend_native_was_refunded_maker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let maker_refunds_payment_args = RefundPaymentArgs { payment_tx: &tx.tx_hex(), time_lock, @@ -1549,7 +1513,7 @@ fn test_search_for_segwit_swap_tx_spend_native_was_refunded_maker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -1587,7 +1551,7 @@ fn test_search_for_segwit_swap_tx_spend_native_was_refunded_taker() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_taker_payment(taker_payment).wait().unwrap(); + let tx = block_on_f01(coin.send_taker_payment(taker_payment)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx.tx_hex(), @@ -1596,7 +1560,7 @@ fn test_search_for_segwit_swap_tx_spend_native_was_refunded_taker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let maker_refunds_payment_args = RefundPaymentArgs { payment_tx: &tx.tx_hex(), time_lock, @@ -1617,7 +1581,7 @@ fn test_search_for_segwit_swap_tx_spend_native_was_refunded_taker() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock, @@ -1741,26 +1705,23 @@ fn test_send_taker_fee_qtum() { generate_segwit_qtum_coin_with_random_privkey("QTUM", BigDecimal::try_from(0.5).unwrap(), Some(0)); let amount = BigDecimal::from_str("0.01").unwrap(); - let tx = coin - .send_taker_fee( - &DEX_FEE_ADDR_RAW_PUBKEY, - DexFee::Standard(amount.clone().into()), - &[], - 0, - ) - .wait() - .expect("!send_taker_fee"); + let tx = block_on_f01(coin.send_taker_fee( + &DEX_FEE_ADDR_RAW_PUBKEY, + DexFee::Standard(amount.clone().into()), + &[], + 0, + )) + .expect("!send_taker_fee"); assert!(matches!(tx, TransactionEnum::UtxoTx(_)), "Expected UtxoTx"); - coin.validate_fee(ValidateFeeArgs { + block_on_f01(coin.validate_fee(ValidateFeeArgs { fee_tx: &tx, expected_sender: coin.my_public_key().unwrap(), fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, dex_fee: &DexFee::Standard(amount.into()), min_block_number: 0, uuid: &[], - }) - .wait() + })) .expect("!validate_fee"); } @@ -1773,25 +1734,22 @@ fn test_send_taker_fee_qrc20() { ); let amount = BigDecimal::from_str("0.01").unwrap(); - let tx = coin - .send_taker_fee( - &DEX_FEE_ADDR_RAW_PUBKEY, - DexFee::Standard(amount.clone().into()), - &[], - 0, - ) - .wait() - .expect("!send_taker_fee"); + let tx = block_on_f01(coin.send_taker_fee( + &DEX_FEE_ADDR_RAW_PUBKEY, + DexFee::Standard(amount.clone().into()), + &[], + 0, + )) + .expect("!send_taker_fee"); assert!(matches!(tx, TransactionEnum::UtxoTx(_)), "Expected UtxoTx"); - coin.validate_fee(ValidateFeeArgs { + block_on_f01(coin.validate_fee(ValidateFeeArgs { fee_tx: &tx, expected_sender: coin.my_public_key().unwrap(), fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY, dex_fee: &DexFee::Standard(amount.into()), min_block_number: 0, uuid: &[], - }) - .wait() + })) .expect("!validate_fee"); } diff --git a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs index 672ef88aa5..46d950242d 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs @@ -6,8 +6,7 @@ use coins::{ConfirmPaymentInput, DexFee, FundingTxSpend, GenTakerFundingSpendArg RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, RefundTakerPaymentArgs, SendMakerPaymentArgs, SendTakerFundingArgs, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, Transaction, ValidateMakerPaymentArgs, ValidateTakerFundingArgs}; -use common::{block_on, now_sec, DEX_FEE_ADDR_RAW_PUBKEY}; -use futures01::Future; +use common::{block_on, block_on_f01, now_sec, DEX_FEE_ADDR_RAW_PUBKEY}; use mm2_number::MmNumber; use mm2_test_helpers::for_tests::{active_swaps, check_recent_swaps, coins_needed_for_kickstart, disable_coin, disable_coin_err, enable_native, get_locked_amount, mm_dump, my_swap_status, @@ -93,7 +92,7 @@ fn send_and_refund_taker_funding_timelock() { wait_until: now_sec() + 20, check_every: 1, }; - coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_input)).unwrap(); let found_refund_tx = block_on(coin.search_for_taker_funding_spend(&taker_funding_utxo_tx, 1, taker_secret_hash)).unwrap(); @@ -180,7 +179,7 @@ fn send_and_refund_taker_funding_secret() { wait_until: now_sec() + 20, check_every: 1, }; - coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_input)).unwrap(); let found_refund_tx = block_on(coin.search_for_taker_funding_spend(&taker_funding_utxo_tx, 1, taker_secret_hash)).unwrap(); @@ -268,7 +267,7 @@ fn send_and_spend_taker_funding() { wait_until: now_sec() + 20, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_input)).unwrap(); let found_spend_tx = block_on(taker_coin.search_for_taker_funding_spend(&taker_funding_utxo_tx, 1, taker_secret_hash)).unwrap(); diff --git a/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs index 22c17c1444..aadda99709 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs @@ -13,9 +13,8 @@ use coins::{ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, MmCoin, MmCoin INVALID_CONTRACT_ADDRESS_ERR_LOG, INVALID_PAYMENT_STATE_ERR_LOG, INVALID_RECEIVER_ERR_LOG, INVALID_REFUND_TX_ERR_LOG, INVALID_SCRIPT_ERR_LOG, INVALID_SENDER_ERR_LOG, INVALID_SWAP_ID_ERR_LOG, OLD_TRANSACTION_ERR_LOG}; -use common::{block_on, now_sec, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY}; +use common::{block_on, block_on_f01, now_sec, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY}; use crypto::privkey::{key_pair_from_secret, key_pair_from_seed}; -use futures01::Future; use mm2_main::lp_swap::{dex_fee_amount, dex_fee_amount_from_taker_coin, generate_secret, get_payment_locktime, MAKER_PAYMENT_SENT_LOG, MAKER_PAYMENT_SPEND_FOUND_LOG, MAKER_PAYMENT_SPEND_SENT_LOG, REFUND_TEST_FAILURE_LOG, TAKER_PAYMENT_REFUND_SENT_LOG, WATCHER_MESSAGE_SENT_LOG}; @@ -1208,15 +1207,13 @@ fn test_watcher_validate_taker_fee_utxo() { let taker_amount = MmNumber::from((10, 1)); let fee_amount = dex_fee_amount_from_taker_coin(&taker_coin, maker_coin.ticker(), &taker_amount); - let taker_fee = taker_coin - .send_taker_fee( - &DEX_FEE_ADDR_RAW_PUBKEY, - fee_amount, - Uuid::new_v4().as_bytes(), - lock_duration, - ) - .wait() - .unwrap(); + let taker_fee = block_on_f01(taker_coin.send_taker_fee( + &DEX_FEE_ADDR_RAW_PUBKEY, + fee_amount, + Uuid::new_v4().as_bytes(), + lock_duration, + )) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_fee.tx_hex(), @@ -1226,30 +1223,26 @@ fn test_watcher_validate_taker_fee_utxo() { check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let validate_taker_fee_res = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: 0, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait(); + let validate_taker_fee_res = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: 0, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })); assert!(validate_taker_fee_res.is_ok()); - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: maker_coin.my_public_key().unwrap().to_vec(), - min_block_number: 0, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: maker_coin.my_public_key().unwrap().to_vec(), + min_block_number: 0, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { @@ -1259,17 +1252,15 @@ fn test_watcher_validate_taker_fee_utxo() { _ => panic!("Expected `WrongPaymentTx` invalid public key, found {:?}", error), } - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: std::u64::MAX, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: std::u64::MAX, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1281,17 +1272,15 @@ fn test_watcher_validate_taker_fee_utxo() { ), } - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: 0, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration: 0, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: 0, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration: 0, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1300,17 +1289,15 @@ fn test_watcher_validate_taker_fee_utxo() { _ => panic!("Expected `WrongPaymentTx` transaction too old, found {:?}", error), } - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: 0, - fee_addr: taker_pubkey.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: 0, + fee_addr: taker_pubkey.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1334,15 +1321,13 @@ fn test_watcher_validate_taker_fee_eth() { let taker_amount = MmNumber::from((1, 1)); let fee_amount = dex_fee_amount_from_taker_coin(&taker_coin, "ETH", &taker_amount); - let taker_fee = taker_coin - .send_taker_fee( - &DEX_FEE_ADDR_RAW_PUBKEY, - fee_amount, - Uuid::new_v4().as_bytes(), - lock_duration, - ) - .wait() - .unwrap(); + let taker_fee = block_on_f01(taker_coin.send_taker_fee( + &DEX_FEE_ADDR_RAW_PUBKEY, + fee_amount, + Uuid::new_v4().as_bytes(), + lock_duration, + )) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_fee.tx_hex(), @@ -1351,31 +1336,27 @@ fn test_watcher_validate_taker_fee_eth() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); - - let validate_taker_fee_res = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: 0, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); + + let validate_taker_fee_res = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: 0, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })); assert!(validate_taker_fee_res.is_ok()); let wrong_keypair = key_pair_from_secret(random_secp256k1_secret().as_slice()).unwrap(); - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: wrong_keypair.public().to_vec(), - min_block_number: 0, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: wrong_keypair.public().to_vec(), + min_block_number: 0, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { @@ -1385,17 +1366,15 @@ fn test_watcher_validate_taker_fee_eth() { _ => panic!("Expected `WrongPaymentTx` invalid public key, found {:?}", error), } - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: std::u64::MAX, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: std::u64::MAX, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1407,17 +1386,15 @@ fn test_watcher_validate_taker_fee_eth() { ), } - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: 0, - fee_addr: taker_pubkey.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: 0, + fee_addr: taker_pubkey.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1441,15 +1418,13 @@ fn test_watcher_validate_taker_fee_erc20() { let taker_amount = MmNumber::from((1, 1)); let fee_amount = dex_fee_amount_from_taker_coin(&taker_coin, "ETH", &taker_amount); - let taker_fee = taker_coin - .send_taker_fee( - &DEX_FEE_ADDR_RAW_PUBKEY, - fee_amount, - Uuid::new_v4().as_bytes(), - lock_duration, - ) - .wait() - .unwrap(); + let taker_fee = block_on_f01(taker_coin.send_taker_fee( + &DEX_FEE_ADDR_RAW_PUBKEY, + fee_amount, + Uuid::new_v4().as_bytes(), + lock_duration, + )) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_fee.tx_hex(), @@ -1458,31 +1433,27 @@ fn test_watcher_validate_taker_fee_erc20() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); - - let validate_taker_fee_res = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: 0, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); + + let validate_taker_fee_res = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: 0, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })); assert!(validate_taker_fee_res.is_ok()); let wrong_keypair = key_pair_from_secret(random_secp256k1_secret().as_slice()).unwrap(); - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: wrong_keypair.public().to_vec(), - min_block_number: 0, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: wrong_keypair.public().to_vec(), + min_block_number: 0, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { @@ -1492,17 +1463,15 @@ fn test_watcher_validate_taker_fee_erc20() { _ => panic!("Expected `WrongPaymentTx` invalid public key, found {:?}", error), } - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: std::u64::MAX, - fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: std::u64::MAX, + fee_addr: DEX_FEE_ADDR_RAW_PUBKEY.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1514,17 +1483,15 @@ fn test_watcher_validate_taker_fee_erc20() { ), } - let error = taker_coin - .watcher_validate_taker_fee(WatcherValidateTakerFeeInput { - taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), - sender_pubkey: taker_pubkey.to_vec(), - min_block_number: 0, - fee_addr: taker_pubkey.to_vec(), - lock_duration, - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_fee(WatcherValidateTakerFeeInput { + taker_fee_hash: taker_fee.tx_hash_as_bytes().into_vec(), + sender_pubkey: taker_pubkey.to_vec(), + min_block_number: 0, + fee_addr: taker_pubkey.to_vec(), + lock_duration, + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1552,21 +1519,19 @@ fn test_watcher_validate_taker_payment_utxo() { let secret_hash = dhash160(&generate_secret().unwrap()); - let taker_payment = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pubkey, - secret_hash: secret_hash.as_slice(), - amount: BigDecimal::from(10), - swap_contract_address: &None, - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: None, - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pubkey, + secret_hash: secret_hash.as_slice(), + amount: BigDecimal::from(10), + swap_contract_address: &None, + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: None, + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment.tx_hex(), @@ -1575,21 +1540,19 @@ fn test_watcher_validate_taker_payment_utxo() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let taker_payment_refund_preimage = taker_coin - .create_taker_payment_refund_preimage( - &taker_payment.tx_hex(), - time_lock, - maker_pubkey, - secret_hash.as_slice(), - &None, - &[], - ) - .wait() - .unwrap(); - let validate_taker_payment_res = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { + let taker_payment_refund_preimage = block_on_f01(taker_coin.create_taker_payment_refund_preimage( + &taker_payment.tx_hex(), + time_lock, + maker_pubkey, + secret_hash.as_slice(), + &None, + &[], + )) + .unwrap(); + let validate_taker_payment_res = + block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { payment_tx: taker_payment.tx_hex(), taker_payment_refund_preimage: taker_payment_refund_preimage.tx_hex(), time_lock, @@ -1599,25 +1562,22 @@ fn test_watcher_validate_taker_payment_utxo() { wait_until: timeout, confirmations: 1, maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), - }) - .wait(); + })); assert!(validate_taker_payment_res.is_ok()); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: taker_payment_refund_preimage.tx_hex(), - time_lock, - taker_pub: maker_pubkey.to_vec(), - maker_pub: maker_pubkey.to_vec(), - secret_hash: secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: taker_payment_refund_preimage.tx_hex(), + time_lock, + taker_pub: maker_pubkey.to_vec(), + maker_pub: maker_pubkey.to_vec(), + secret_hash: secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { @@ -1629,21 +1589,19 @@ fn test_watcher_validate_taker_payment_utxo() { // Used to get wrong swap id let wrong_secret_hash = dhash160(&generate_secret().unwrap()); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: taker_payment_refund_preimage.tx_hex(), - time_lock, - taker_pub: taker_pubkey.to_vec(), - maker_pub: maker_pubkey.to_vec(), - secret_hash: wrong_secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: taker_payment_refund_preimage.tx_hex(), + time_lock, + taker_pub: taker_pubkey.to_vec(), + maker_pub: maker_pubkey.to_vec(), + secret_hash: wrong_secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { @@ -1656,21 +1614,19 @@ fn test_watcher_validate_taker_payment_utxo() { ), } - let taker_payment_wrong_secret = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pubkey, - secret_hash: wrong_secret_hash.as_slice(), - amount: BigDecimal::from(10), - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: None, - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment_wrong_secret = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pubkey, + secret_hash: wrong_secret_hash.as_slice(), + amount: BigDecimal::from(10), + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: None, + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment_wrong_secret.tx_hex(), @@ -1679,23 +1635,21 @@ fn test_watcher_validate_taker_payment_utxo() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: taker_payment_refund_preimage.tx_hex(), - time_lock: 500, - taker_pub: taker_pubkey.to_vec(), - maker_pub: maker_pubkey.to_vec(), - secret_hash: wrong_secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: taker_payment_refund_preimage.tx_hex(), + time_lock: 500, + taker_pub: taker_pubkey.to_vec(), + maker_pub: maker_pubkey.to_vec(), + secret_hash: wrong_secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { @@ -1708,33 +1662,29 @@ fn test_watcher_validate_taker_payment_utxo() { ), } - let wrong_taker_payment_refund_preimage = taker_coin - .create_taker_payment_refund_preimage( - &taker_payment.tx_hex(), - time_lock, - maker_pubkey, - wrong_secret_hash.as_slice(), - &None, - &[], - ) - .wait() - .unwrap(); + let wrong_taker_payment_refund_preimage = block_on_f01(taker_coin.create_taker_payment_refund_preimage( + &taker_payment.tx_hex(), + time_lock, + maker_pubkey, + wrong_secret_hash.as_slice(), + &None, + &[], + )) + .unwrap(); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: wrong_taker_payment_refund_preimage.tx_hex(), - time_lock, - taker_pub: taker_pubkey.to_vec(), - maker_pub: maker_pubkey.to_vec(), - secret_hash: secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: wrong_taker_payment_refund_preimage.tx_hex(), + time_lock, + taker_pub: taker_pubkey.to_vec(), + maker_pub: maker_pubkey.to_vec(), + secret_hash: secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::UtxoCoin(maker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { @@ -1777,21 +1727,19 @@ fn test_watcher_validate_taker_payment_eth() { .unwrap(), ); - let taker_payment = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pub, - secret_hash: secret_hash.as_slice(), - amount: taker_amount.clone(), - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: watcher_reward.clone(), - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pub, + secret_hash: secret_hash.as_slice(), + amount: taker_amount.clone(), + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: watcher_reward.clone(), + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment.tx_hex(), @@ -1800,10 +1748,10 @@ fn test_watcher_validate_taker_payment_eth() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let validate_taker_payment_res = taker_coin - .watcher_validate_taker_payment(coins::WatcherValidatePaymentInput { + let validate_taker_payment_res = block_on_f01(taker_coin.watcher_validate_taker_payment( + coins::WatcherValidatePaymentInput { payment_tx: taker_payment.tx_hex(), taker_payment_refund_preimage: Vec::new(), time_lock, @@ -1813,12 +1761,12 @@ fn test_watcher_validate_taker_payment_eth() { wait_until: timeout, confirmations: 1, maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait(); + }, + )); assert!(validate_taker_payment_res.is_ok()); - let error = taker_coin - .watcher_validate_taker_payment(coins::WatcherValidatePaymentInput { + let error = block_on_f01( + taker_coin.watcher_validate_taker_payment(coins::WatcherValidatePaymentInput { payment_tx: taker_payment.tx_hex(), taker_payment_refund_preimage: Vec::new(), time_lock, @@ -1828,10 +1776,10 @@ fn test_watcher_validate_taker_payment_eth() { wait_until: timeout, confirmations: 1, maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + }), + ) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1843,24 +1791,22 @@ fn test_watcher_validate_taker_payment_eth() { ), } - let taker_payment_wrong_contract = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pub, - secret_hash: secret_hash.as_slice(), - amount: taker_amount.clone(), - swap_contract_address: &Some("9130b257d37a52e52f21054c4da3450c72f595ce".into()), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: watcher_reward.clone(), - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment_wrong_contract = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pub, + secret_hash: secret_hash.as_slice(), + amount: taker_amount.clone(), + swap_contract_address: &Some("9130b257d37a52e52f21054c4da3450c72f595ce".into()), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: watcher_reward.clone(), + wait_for_confirmation_until, + })) + .unwrap(); - let error = taker_coin - .watcher_validate_taker_payment(coins::WatcherValidatePaymentInput { + let error = block_on_f01( + taker_coin.watcher_validate_taker_payment(coins::WatcherValidatePaymentInput { payment_tx: taker_payment_wrong_contract.tx_hex(), taker_payment_refund_preimage: Vec::new(), time_lock, @@ -1870,10 +1816,10 @@ fn test_watcher_validate_taker_payment_eth() { wait_until: timeout, confirmations: 1, maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + }), + ) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1887,8 +1833,8 @@ fn test_watcher_validate_taker_payment_eth() { // Used to get wrong swap id let wrong_secret_hash = dhash160(&generate_secret().unwrap()); - let error = taker_coin - .watcher_validate_taker_payment(coins::WatcherValidatePaymentInput { + let error = block_on_f01( + taker_coin.watcher_validate_taker_payment(coins::WatcherValidatePaymentInput { payment_tx: taker_payment.tx_hex(), taker_payment_refund_preimage: Vec::new(), time_lock, @@ -1898,10 +1844,10 @@ fn test_watcher_validate_taker_payment_eth() { wait_until: timeout, confirmations: 1, maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + }), + ) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::UnexpectedPaymentState(err) => { @@ -1913,21 +1859,19 @@ fn test_watcher_validate_taker_payment_eth() { ), } - let taker_payment_wrong_secret = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pub, - secret_hash: wrong_secret_hash.as_slice(), - amount: taker_amount, - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward, - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment_wrong_secret = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pub, + secret_hash: wrong_secret_hash.as_slice(), + amount: taker_amount, + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward, + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment_wrong_secret.tx_hex(), @@ -1936,23 +1880,21 @@ fn test_watcher_validate_taker_payment_eth() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: Vec::new(), - time_lock, - taker_pub: taker_pub.to_vec(), - maker_pub: maker_pub.to_vec(), - secret_hash: wrong_secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: Vec::new(), + time_lock, + taker_pub: taker_pub.to_vec(), + maker_pub: maker_pub.to_vec(), + secret_hash: wrong_secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -1964,21 +1906,19 @@ fn test_watcher_validate_taker_payment_eth() { ), } - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: Vec::new(), - time_lock, - taker_pub: taker_pub.to_vec(), - maker_pub: taker_pub.to_vec(), - secret_hash: secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: Vec::new(), + time_lock, + taker_pub: taker_pub.to_vec(), + maker_pub: taker_pub.to_vec(), + secret_hash: secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -2023,21 +1963,19 @@ fn test_watcher_validate_taker_payment_erc20() { .unwrap(), ); - let taker_payment = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pub, - secret_hash: secret_hash.as_slice(), - amount: taker_amount.clone(), - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: watcher_reward.clone(), - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pub, + secret_hash: secret_hash.as_slice(), + amount: taker_amount.clone(), + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: watcher_reward.clone(), + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment.tx_hex(), @@ -2046,10 +1984,10 @@ fn test_watcher_validate_taker_payment_erc20() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let validate_taker_payment_res = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { + let validate_taker_payment_res = + block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { payment_tx: taker_payment.tx_hex(), taker_payment_refund_preimage: Vec::new(), time_lock, @@ -2059,25 +1997,22 @@ fn test_watcher_validate_taker_payment_erc20() { wait_until: timeout, confirmations: 1, maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait(); + })); assert!(validate_taker_payment_res.is_ok()); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: Vec::new(), - time_lock, - taker_pub: maker_pub.to_vec(), - maker_pub: maker_pub.to_vec(), - secret_hash: secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: Vec::new(), + time_lock, + taker_pub: maker_pub.to_vec(), + maker_pub: maker_pub.to_vec(), + secret_hash: secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -2089,37 +2024,33 @@ fn test_watcher_validate_taker_payment_erc20() { ), } - let taker_payment_wrong_contract = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pub, - secret_hash: secret_hash.as_slice(), - amount: taker_amount.clone(), - swap_contract_address: &Some("9130b257d37a52e52f21054c4da3450c72f595ce".into()), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: watcher_reward.clone(), - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment_wrong_contract = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pub, + secret_hash: secret_hash.as_slice(), + amount: taker_amount.clone(), + swap_contract_address: &Some("9130b257d37a52e52f21054c4da3450c72f595ce".into()), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: watcher_reward.clone(), + wait_for_confirmation_until, + })) + .unwrap(); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment_wrong_contract.tx_hex(), - taker_payment_refund_preimage: Vec::new(), - time_lock, - taker_pub: taker_pub.to_vec(), - maker_pub: maker_pub.to_vec(), - secret_hash: secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment_wrong_contract.tx_hex(), + taker_payment_refund_preimage: Vec::new(), + time_lock, + taker_pub: taker_pub.to_vec(), + maker_pub: maker_pub.to_vec(), + secret_hash: secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -2133,21 +2064,19 @@ fn test_watcher_validate_taker_payment_erc20() { // Used to get wrong swap id let wrong_secret_hash = dhash160(&generate_secret().unwrap()); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: Vec::new(), - time_lock, - taker_pub: taker_pub.to_vec(), - maker_pub: maker_pub.to_vec(), - secret_hash: wrong_secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: Vec::new(), + time_lock, + taker_pub: taker_pub.to_vec(), + maker_pub: maker_pub.to_vec(), + secret_hash: wrong_secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::UnexpectedPaymentState(err) => { @@ -2159,21 +2088,19 @@ fn test_watcher_validate_taker_payment_erc20() { ), } - let taker_payment_wrong_secret = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pub, - secret_hash: wrong_secret_hash.as_slice(), - amount: taker_amount, - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward, - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment_wrong_secret = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pub, + secret_hash: wrong_secret_hash.as_slice(), + amount: taker_amount, + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward, + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment_wrong_secret.tx_hex(), @@ -2182,23 +2109,21 @@ fn test_watcher_validate_taker_payment_erc20() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: Vec::new(), - time_lock, - taker_pub: taker_pub.to_vec(), - maker_pub: maker_pub.to_vec(), - secret_hash: wrong_secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: Vec::new(), + time_lock, + taker_pub: taker_pub.to_vec(), + maker_pub: maker_pub.to_vec(), + secret_hash: wrong_secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -2210,21 +2135,19 @@ fn test_watcher_validate_taker_payment_erc20() { ), } - let error = taker_coin - .watcher_validate_taker_payment(WatcherValidatePaymentInput { - payment_tx: taker_payment.tx_hex(), - taker_payment_refund_preimage: Vec::new(), - time_lock, - taker_pub: taker_pub.to_vec(), - maker_pub: taker_pub.to_vec(), - secret_hash: secret_hash.to_vec(), - wait_until: timeout, - confirmations: 1, - maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), - }) - .wait() - .unwrap_err() - .into_inner(); + let error = block_on_f01(taker_coin.watcher_validate_taker_payment(WatcherValidatePaymentInput { + payment_tx: taker_payment.tx_hex(), + taker_payment_refund_preimage: Vec::new(), + time_lock, + taker_pub: taker_pub.to_vec(), + maker_pub: taker_pub.to_vec(), + secret_hash: secret_hash.to_vec(), + wait_until: timeout, + confirmations: 1, + maker_coin: MmCoinEnum::EthCoin(taker_coin.clone()), + })) + .unwrap_err() + .into_inner(); log!("error: {:?}", error); match error { ValidatePaymentError::WrongPaymentTx(err) => { @@ -2250,21 +2173,19 @@ fn test_taker_validates_taker_payment_refund_utxo() { let secret_hash = dhash160(&generate_secret().unwrap()); - let taker_payment = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pubkey, - secret_hash: secret_hash.as_slice(), - amount: BigDecimal::from(10), - swap_contract_address: &None, - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: None, - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pubkey, + secret_hash: secret_hash.as_slice(), + amount: BigDecimal::from(10), + swap_contract_address: &None, + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: None, + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment.tx_hex(), @@ -2273,34 +2194,30 @@ fn test_taker_validates_taker_payment_refund_utxo() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let taker_payment_refund_preimage = taker_coin - .create_taker_payment_refund_preimage( - &taker_payment.tx_hex(), - time_lock, - maker_pubkey, - secret_hash.as_slice(), - &None, - &[], - ) - .wait() - .unwrap(); + let taker_payment_refund_preimage = block_on_f01(taker_coin.create_taker_payment_refund_preimage( + &taker_payment.tx_hex(), + time_lock, + maker_pubkey, + secret_hash.as_slice(), + &None, + &[], + )) + .unwrap(); - let taker_payment_refund = taker_coin - .send_taker_payment_refund_preimage(RefundPaymentArgs { - payment_tx: &taker_payment_refund_preimage.tx_hex(), - other_pubkey: maker_pubkey, - tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerOrMakerPayment { - maker_secret_hash: secret_hash.as_slice(), - }, - time_lock, - swap_contract_address: &None, - swap_unique_data: &[], - watcher_reward: false, - }) - .wait() - .unwrap(); + let taker_payment_refund = block_on_f01(taker_coin.send_taker_payment_refund_preimage(RefundPaymentArgs { + payment_tx: &taker_payment_refund_preimage.tx_hex(), + other_pubkey: maker_pubkey, + tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerOrMakerPayment { + maker_secret_hash: secret_hash.as_slice(), + }, + time_lock, + swap_contract_address: &None, + swap_unique_data: &[], + watcher_reward: false, + })) + .unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: taker_payment_refund.tx_hex(), @@ -2313,9 +2230,7 @@ fn test_taker_validates_taker_payment_refund_utxo() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let validate_watcher_refund = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait(); + let validate_watcher_refund = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)); assert!(validate_watcher_refund.is_ok()); } @@ -2347,21 +2262,19 @@ fn test_taker_validates_taker_payment_refund_eth() { )) .unwrap(); - let taker_payment = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pub, - secret_hash: secret_hash.as_slice(), - amount: taker_amount.clone(), - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: Some(watcher_reward.clone()), - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pub, + secret_hash: secret_hash.as_slice(), + amount: taker_amount.clone(), + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: Some(watcher_reward.clone()), + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment.tx_hex(), @@ -2370,19 +2283,17 @@ fn test_taker_validates_taker_payment_refund_eth() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let taker_payment_refund_preimage = taker_coin - .create_taker_payment_refund_preimage( - &taker_payment.tx_hex(), - time_lock, - taker_pub, - secret_hash.as_slice(), - &taker_coin.swap_contract_address(), - &[], - ) - .wait() - .unwrap(); + let taker_payment_refund_preimage = block_on_f01(taker_coin.create_taker_payment_refund_preimage( + &taker_payment.tx_hex(), + time_lock, + taker_pub, + secret_hash.as_slice(), + &taker_coin.swap_contract_address(), + &[], + )) + .unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: taker_payment_refund_preimage.tx_hex(), @@ -2395,9 +2306,7 @@ fn test_taker_validates_taker_payment_refund_eth() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2411,20 +2320,18 @@ fn test_taker_validates_taker_payment_refund_eth() { ), } - let taker_payment_refund = taker_coin - .send_taker_payment_refund_preimage(RefundPaymentArgs { - payment_tx: &taker_payment_refund_preimage.tx_hex(), - other_pubkey: taker_pub, - tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerOrMakerPayment { - maker_secret_hash: secret_hash.as_slice(), - }, - time_lock, - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - watcher_reward: true, - }) - .wait() - .unwrap(); + let taker_payment_refund = block_on_f01(taker_coin.send_taker_payment_refund_preimage(RefundPaymentArgs { + payment_tx: &taker_payment_refund_preimage.tx_hex(), + other_pubkey: taker_pub, + tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerOrMakerPayment { + maker_secret_hash: secret_hash.as_slice(), + }, + time_lock, + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + watcher_reward: true, + })) + .unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: taker_payment_refund.tx_hex(), @@ -2437,9 +2344,7 @@ fn test_taker_validates_taker_payment_refund_eth() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let validate_watcher_refund = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait(); + let validate_watcher_refund = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)); assert!(validate_watcher_refund.is_ok()); let validate_input = ValidateWatcherSpendInput { @@ -2452,9 +2357,7 @@ fn test_taker_validates_taker_payment_refund_eth() { watcher_reward: Some(watcher_reward.clone()), spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2479,9 +2382,7 @@ fn test_taker_validates_taker_payment_refund_eth() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = maker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(maker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2506,9 +2407,7 @@ fn test_taker_validates_taker_payment_refund_eth() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2536,9 +2435,7 @@ fn test_taker_validates_taker_payment_refund_eth() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2566,9 +2463,7 @@ fn test_taker_validates_taker_payment_refund_eth() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2596,9 +2491,7 @@ fn test_taker_validates_taker_payment_refund_eth() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2623,9 +2516,7 @@ fn test_taker_validates_taker_payment_refund_eth() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2672,21 +2563,19 @@ fn test_taker_validates_taker_payment_refund_erc20() { .unwrap(), ); - let taker_payment = taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: maker_pub, - secret_hash: secret_hash.as_slice(), - amount: taker_amount.clone(), - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: watcher_reward.clone(), - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let taker_payment = block_on_f01(taker_coin.send_taker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: maker_pub, + secret_hash: secret_hash.as_slice(), + amount: taker_amount.clone(), + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: watcher_reward.clone(), + wait_for_confirmation_until, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: taker_payment.tx_hex(), @@ -2695,34 +2584,30 @@ fn test_taker_validates_taker_payment_refund_erc20() { wait_until: timeout, check_every: 1, }; - taker_coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(taker_coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let taker_payment_refund_preimage = taker_coin - .create_taker_payment_refund_preimage( - &taker_payment.tx_hex(), - time_lock, - taker_pub, - secret_hash.as_slice(), - &taker_coin.swap_contract_address(), - &[], - ) - .wait() - .unwrap(); + let taker_payment_refund_preimage = block_on_f01(taker_coin.create_taker_payment_refund_preimage( + &taker_payment.tx_hex(), + time_lock, + taker_pub, + secret_hash.as_slice(), + &taker_coin.swap_contract_address(), + &[], + )) + .unwrap(); - let taker_payment_refund = taker_coin - .send_taker_payment_refund_preimage(RefundPaymentArgs { - payment_tx: &taker_payment_refund_preimage.tx_hex(), - other_pubkey: taker_pub, - tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerOrMakerPayment { - maker_secret_hash: secret_hash.as_slice(), - }, - time_lock, - swap_contract_address: &taker_coin.swap_contract_address(), - swap_unique_data: &[], - watcher_reward: true, - }) - .wait() - .unwrap(); + let taker_payment_refund = block_on_f01(taker_coin.send_taker_payment_refund_preimage(RefundPaymentArgs { + payment_tx: &taker_payment_refund_preimage.tx_hex(), + other_pubkey: taker_pub, + tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerOrMakerPayment { + maker_secret_hash: secret_hash.as_slice(), + }, + time_lock, + swap_contract_address: &taker_coin.swap_contract_address(), + swap_unique_data: &[], + watcher_reward: true, + })) + .unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: taker_payment_refund.tx_hex(), @@ -2735,9 +2620,7 @@ fn test_taker_validates_taker_payment_refund_erc20() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let validate_watcher_refund = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait(); + let validate_watcher_refund = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)); assert!(validate_watcher_refund.is_ok()); let validate_input = ValidateWatcherSpendInput { @@ -2751,9 +2634,7 @@ fn test_taker_validates_taker_payment_refund_erc20() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2783,54 +2664,48 @@ fn test_taker_validates_maker_payment_spend_utxo() { let secret = generate_secret().unwrap(); let secret_hash = dhash160(&secret); - let maker_payment = maker_coin - .send_maker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: taker_pubkey, - secret_hash: secret_hash.as_slice(), - amount: BigDecimal::from(10), - swap_contract_address: &None, - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: None, - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let maker_payment = block_on_f01(maker_coin.send_maker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: taker_pubkey, + secret_hash: secret_hash.as_slice(), + amount: BigDecimal::from(10), + swap_contract_address: &None, + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: None, + wait_for_confirmation_until, + })) + .unwrap(); - maker_coin - .wait_for_confirmations(ConfirmPaymentInput { - payment_tx: maker_payment.tx_hex(), - confirmations: 1, - requires_nota: false, - wait_until: timeout, - check_every: 1, - }) - .wait() - .unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(ConfirmPaymentInput { + payment_tx: maker_payment.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: timeout, + check_every: 1, + })) + .unwrap(); - let maker_payment_spend_preimage = taker_coin - .create_maker_payment_spend_preimage( - &maker_payment.tx_hex(), - time_lock, - maker_pubkey, - secret_hash.as_slice(), - &[], - ) - .wait() - .unwrap(); + let maker_payment_spend_preimage = block_on_f01(taker_coin.create_maker_payment_spend_preimage( + &maker_payment.tx_hex(), + time_lock, + maker_pubkey, + secret_hash.as_slice(), + &[], + )) + .unwrap(); - let maker_payment_spend = taker_coin - .send_maker_payment_spend_preimage(SendMakerPaymentSpendPreimageInput { + let maker_payment_spend = block_on_f01(taker_coin.send_maker_payment_spend_preimage( + SendMakerPaymentSpendPreimageInput { preimage: &maker_payment_spend_preimage.tx_hex(), secret_hash: secret_hash.as_slice(), secret: secret.as_slice(), taker_pub: taker_pubkey, watcher_reward: false, - }) - .wait() - .unwrap(); + }, + )) + .unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: maker_payment_spend.tx_hex(), @@ -2843,9 +2718,7 @@ fn test_taker_validates_maker_payment_spend_utxo() { spend_type: WatcherSpendType::TakerPaymentRefund, }; - let validate_watcher_spend = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait(); + let validate_watcher_spend = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)); assert!(validate_watcher_spend.is_ok()); } @@ -2877,43 +2750,37 @@ fn test_taker_validates_maker_payment_spend_eth() { .unwrap() .unwrap(); - let maker_payment = maker_coin - .send_maker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: taker_pub, - secret_hash: secret_hash.as_slice(), - amount: maker_amount.clone(), - swap_contract_address: &maker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: Some(watcher_reward.clone()), - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let maker_payment = block_on_f01(maker_coin.send_maker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: taker_pub, + secret_hash: secret_hash.as_slice(), + amount: maker_amount.clone(), + swap_contract_address: &maker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: Some(watcher_reward.clone()), + wait_for_confirmation_until, + })) + .unwrap(); - maker_coin - .wait_for_confirmations(ConfirmPaymentInput { - payment_tx: maker_payment.tx_hex(), - confirmations: 1, - requires_nota: false, - wait_until: timeout, - check_every: 1, - }) - .wait() - .unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(ConfirmPaymentInput { + payment_tx: maker_payment.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: timeout, + check_every: 1, + })) + .unwrap(); - let maker_payment_spend_preimage = taker_coin - .create_maker_payment_spend_preimage( - &maker_payment.tx_hex(), - time_lock, - maker_pub, - secret_hash.as_slice(), - &[], - ) - .wait() - .unwrap(); + let maker_payment_spend_preimage = block_on_f01(taker_coin.create_maker_payment_spend_preimage( + &maker_payment.tx_hex(), + time_lock, + maker_pub, + secret_hash.as_slice(), + &[], + )) + .unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: maker_payment_spend_preimage.tx_hex(), @@ -2926,9 +2793,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -2942,27 +2807,25 @@ fn test_taker_validates_maker_payment_spend_eth() { ), } - let maker_payment_spend = taker_coin - .send_maker_payment_spend_preimage(SendMakerPaymentSpendPreimageInput { + let maker_payment_spend = block_on_f01(taker_coin.send_maker_payment_spend_preimage( + SendMakerPaymentSpendPreimageInput { preimage: &maker_payment_spend_preimage.tx_hex(), secret_hash: secret_hash.as_slice(), secret: secret.as_slice(), taker_pub, watcher_reward: true, - }) - .wait() - .unwrap(); + }, + )) + .unwrap(); - maker_coin - .wait_for_confirmations(ConfirmPaymentInput { - payment_tx: maker_payment_spend.tx_hex(), - confirmations: 1, - requires_nota: false, - wait_until: timeout, - check_every: 1, - }) - .wait() - .unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(ConfirmPaymentInput { + payment_tx: maker_payment_spend.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: timeout, + check_every: 1, + })) + .unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: maker_payment_spend.tx_hex(), @@ -2975,10 +2838,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() - .unwrap(); + block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)).unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: maker_payment_spend.tx_hex(), @@ -2991,9 +2851,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -3018,9 +2876,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -3045,9 +2901,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = maker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(maker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -3075,9 +2929,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -3105,9 +2957,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -3135,9 +2985,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -3162,9 +3010,7 @@ fn test_taker_validates_maker_payment_spend_eth() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -3206,65 +3052,57 @@ fn test_taker_validates_maker_payment_spend_erc20() { )) .unwrap(); - let maker_payment = maker_coin - .send_maker_payment(SendPaymentArgs { - time_lock_duration, - time_lock, - other_pubkey: taker_pub, - secret_hash: secret_hash.as_slice(), - amount: maker_amount.clone(), - swap_contract_address: &maker_coin.swap_contract_address(), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: watcher_reward.clone(), - wait_for_confirmation_until, - }) - .wait() - .unwrap(); + let maker_payment = block_on_f01(maker_coin.send_maker_payment(SendPaymentArgs { + time_lock_duration, + time_lock, + other_pubkey: taker_pub, + secret_hash: secret_hash.as_slice(), + amount: maker_amount.clone(), + swap_contract_address: &maker_coin.swap_contract_address(), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: watcher_reward.clone(), + wait_for_confirmation_until, + })) + .unwrap(); - maker_coin - .wait_for_confirmations(ConfirmPaymentInput { - payment_tx: maker_payment.tx_hex(), - confirmations: 1, - requires_nota: false, - wait_until: timeout, - check_every: 1, - }) - .wait() - .unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(ConfirmPaymentInput { + payment_tx: maker_payment.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: timeout, + check_every: 1, + })) + .unwrap(); - let maker_payment_spend_preimage = taker_coin - .create_maker_payment_spend_preimage( - &maker_payment.tx_hex(), - time_lock, - maker_pub, - secret_hash.as_slice(), - &[], - ) - .wait() - .unwrap(); + let maker_payment_spend_preimage = block_on_f01(taker_coin.create_maker_payment_spend_preimage( + &maker_payment.tx_hex(), + time_lock, + maker_pub, + secret_hash.as_slice(), + &[], + )) + .unwrap(); - let maker_payment_spend = taker_coin - .send_maker_payment_spend_preimage(SendMakerPaymentSpendPreimageInput { + let maker_payment_spend = block_on_f01(taker_coin.send_maker_payment_spend_preimage( + SendMakerPaymentSpendPreimageInput { preimage: &maker_payment_spend_preimage.tx_hex(), secret_hash: secret_hash.as_slice(), secret: secret.as_slice(), taker_pub, watcher_reward: true, - }) - .wait() - .unwrap(); + }, + )) + .unwrap(); - maker_coin - .wait_for_confirmations(ConfirmPaymentInput { - payment_tx: maker_payment_spend.tx_hex(), - confirmations: 1, - requires_nota: false, - wait_until: timeout, - check_every: 1, - }) - .wait() - .unwrap(); + block_on_f01(maker_coin.wait_for_confirmations(ConfirmPaymentInput { + payment_tx: maker_payment_spend.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: timeout, + check_every: 1, + })) + .unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: maker_payment_spend.tx_hex(), @@ -3277,10 +3115,7 @@ fn test_taker_validates_maker_payment_spend_erc20() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() - .unwrap(); + block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)).unwrap(); let validate_input = ValidateWatcherSpendInput { payment_tx: maker_payment_spend.tx_hex(), @@ -3293,9 +3128,7 @@ fn test_taker_validates_maker_payment_spend_erc20() { spend_type: WatcherSpendType::MakerPaymentSpend, }; - let error = taker_coin - .taker_validates_payment_spend_or_refund(validate_input) - .wait() + let error = block_on_f01(taker_coin.taker_validates_payment_spend_or_refund(validate_input)) .unwrap_err() .into_inner(); log!("error: {:?}", error); @@ -3329,7 +3162,7 @@ fn test_send_taker_payment_refund_preimage_utxo() { watcher_reward: None, wait_for_confirmation_until: 0, }; - let tx = coin.send_taker_payment(taker_payment_args).wait().unwrap(); + let tx = block_on_f01(coin.send_taker_payment(taker_payment_args)).unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: tx.tx_hex(), @@ -3338,27 +3171,30 @@ fn test_send_taker_payment_refund_preimage_utxo() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); - let refund_tx = coin - .create_taker_payment_refund_preimage(&tx.tx_hex(), time_lock, my_public_key, &[0; 20], &None, &[]) - .wait() - .unwrap(); + let refund_tx = block_on_f01(coin.create_taker_payment_refund_preimage( + &tx.tx_hex(), + time_lock, + my_public_key, + &[0; 20], + &None, + &[], + )) + .unwrap(); - let refund_tx = coin - .send_taker_payment_refund_preimage(RefundPaymentArgs { - payment_tx: &refund_tx.tx_hex(), - swap_contract_address: &None, - tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerOrMakerPayment { - maker_secret_hash: &[0; 20], - }, - other_pubkey: my_public_key, - time_lock, - swap_unique_data: &[], - watcher_reward: false, - }) - .wait() - .unwrap(); + let refund_tx = block_on_f01(coin.send_taker_payment_refund_preimage(RefundPaymentArgs { + payment_tx: &refund_tx.tx_hex(), + swap_contract_address: &None, + tx_type_with_secret_hash: SwapTxTypeWithSecretHash::TakerOrMakerPayment { + maker_secret_hash: &[0; 20], + }, + other_pubkey: my_public_key, + time_lock, + swap_unique_data: &[], + watcher_reward: false, + })) + .unwrap(); let confirm_payment_input = ConfirmPaymentInput { payment_tx: refund_tx.tx_hex(), @@ -3367,7 +3203,7 @@ fn test_send_taker_payment_refund_preimage_utxo() { wait_until: timeout, check_every: 1, }; - coin.wait_for_confirmations(confirm_payment_input).wait().unwrap(); + block_on_f01(coin.wait_for_confirmations(confirm_payment_input)).unwrap(); let search_input = SearchForSwapTxSpendInput { time_lock,