diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs
index 958fb84337..640dac082d 100644
--- a/mm2src/coins/eth.rs
+++ b/mm2src/coins/eth.rs
@@ -3445,6 +3445,31 @@ impl EthCoin {
         Box::new(fut.boxed().compat())
     }
 
+    async fn sign_and_send_transaction_async(
+        &self,
+        value: U256,
+        action: Action,
+        data: Vec<u8>,
+        gas: U256,
+    ) -> Result<SignedEthTx, TransactionErr> {
+        let ctx = MmArc::from_weak(&self.ctx)
+            .ok_or("!ctx")
+            .map_err(|e| TransactionErr::Plain(e.to_string()))?;
+        let coin = self.clone();
+        match coin.priv_key_policy {
+            EthPrivKeyPolicy::Iguana(ref key_pair)
+            | EthPrivKeyPolicy::HDWallet {
+                activated_key: ref key_pair,
+                ..
+            } => sign_and_send_transaction_with_keypair(ctx, &coin, key_pair, value, action, data, gas).await,
+            EthPrivKeyPolicy::Trezor => Err(TransactionErr::Plain(ERRL!("Trezor is not supported for EVM yet!"))),
+            #[cfg(target_arch = "wasm32")]
+            EthPrivKeyPolicy::Metamask(_) => {
+                sign_and_send_transaction_with_metamask(coin, value, action, data, gas).await
+            },
+        }
+    }
+
     pub fn send_to_address(&self, address: Address, value: U256) -> EthTxFut {
         match &self.coin_type {
             EthCoinType::Eth => self.sign_and_send_transaction(value, Action::Call(address), vec![], U256::from(21000)),
@@ -6387,26 +6412,28 @@ impl EthCoin {
                     let function = ERC1155_CONTRACT.function("safeTransferFrom")?;
                     let amount_u256 = U256::from_dec_str(&args.amount.to_string())
                         .map_err(|e| NumConversError::new(e.to_string()))?;
-                    let _data = function.encode_input(&[
+                    let data = function.encode_input(&[
                         Token::Address(self.my_address),
                         Token::Address(swap_contract_address),
                         Token::Uint(token_id_u256),
                         Token::Uint(amount_u256),
                         Token::Bytes(htlc_data),
                     ])?;
-                    let _gas = U256::from(ETH_GAS);
-                    todo!()
+                    let gas = U256::from(ETH_GAS);
+                    self.sign_and_send_transaction_async(0.into(), Action::Call(token_address), data, gas)
+                        .await
                 },
                 ContractType::Erc721 => {
                     let function = ERC721_CONTRACT.function("safeTransferFrom")?;
-                    let _data = function.encode_input(&[
+                    let data = function.encode_input(&[
                         Token::Address(self.my_address),
                         Token::Address(swap_contract_address),
                         Token::Uint(token_id_u256),
                         Token::Bytes(htlc_data),
                     ])?;
-                    let _gas = U256::from(ETH_GAS);
-                    todo!()
+                    let gas = U256::from(ETH_GAS);
+                    self.sign_and_send_transaction_async(0.into(), Action::Call(token_address), data, gas)
+                        .await
                 },
             },
             EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported(
diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs
index 091daaa4c3..ee52516ea9 100644
--- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs
+++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs
@@ -1,14 +1,15 @@
-use super::eth_docker_tests::{eth_coin_with_random_privkey, global_nft_with_random_privkey, nft_swap_contract};
+use super::eth_docker_tests::{erc721_contract, eth_coin_with_random_privkey, global_nft_with_random_privkey,
+                              nft_swap_contract};
 use coins::eth::EthCoin;
 use coins::nft::nft_structs::{Chain, ContractType};
-use coins::{CoinAssocTypes, SendNftMakerPaymentArgs, SwapOps, ToBytes};
-use common::now_sec;
+use coins::{CoinAssocTypes, MakerNftSwapOpsV2, SendNftMakerPaymentArgs, SwapOps, ToBytes};
+use common::{block_on, now_sec};
 use mm2_number::BigUint;
 
 #[test]
 fn send_and_spend_erc721_maker_payment() {
     // TODO generate pair of utxo & eth coins from same random secret for maker / taker
-    let _maker_global_nft = global_nft_with_random_privkey(nft_swap_contract());
+    let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract());
     // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin,
     // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations.
     // TODO need to add NFT conf in coin conf and refactor enable nft a bit
@@ -17,17 +18,18 @@ fn send_and_spend_erc721_maker_payment() {
     let time_lock = now_sec() - 100;
     let taker_pubkey = taker_eth_coin.derive_htlc_pubkey(&[]);
 
-    let _send_payment_args: SendNftMakerPaymentArgs<EthCoin> = SendNftMakerPaymentArgs {
+    let send_payment_args: SendNftMakerPaymentArgs<EthCoin> = SendNftMakerPaymentArgs {
         time_lock,
-        taker_secret_hash: &[],
-        maker_secret_hash: &[],
+        taker_secret_hash: &[0; 32],
+        maker_secret_hash: &[0; 32],
         amount: 1.into(),
         taker_pub: &taker_eth_coin.parse_pubkey(&taker_pubkey).unwrap(),
         swap_unique_data: &[],
-        token_address: &[],
+        token_address: &erc721_contract().to_bytes(),
         token_id: &BigUint::from(1u32).to_bytes(),
         chain: &Chain::Eth.to_bytes(),
         contract_type: &ContractType::Erc721.to_bytes(),
         swap_contract_address: nft_swap_contract().as_bytes(),
     };
+    block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap();
 }