瀏覽代碼

small refactor of ethereum newSwap event handling

elizabeth 2 年之前
父節點
當前提交
90f4bd92fc

+ 7 - 3
ethereum/src/SwapCreator.sol

@@ -78,10 +78,12 @@ contract SwapCreator is Secp256k1 {
         bytes32 swapID,
         bytes32 claimKey,
         bytes32 refundKey,
+        address claimer,
         uint256 timeout1,
         uint256 timeout2,
         address asset,
-        uint256 value
+        uint256 value,
+        uint256 nonce
     );
     event Ready(bytes32 indexed swapID);
     event Claimed(bytes32 indexed swapID, bytes32 indexed s);
@@ -168,7 +170,7 @@ contract SwapCreator is Secp256k1 {
         bytes32 _claimCommitment,
         bytes32 _refundCommitment,
         address payable _claimer,
-        uint256 _timeoutDuration1,
+        uint256 _timeoutDuration1,  
         uint256 _timeoutDuration2,
         address _asset,
         uint256 _value,
@@ -208,10 +210,12 @@ contract SwapCreator is Secp256k1 {
             swapID,
             _claimCommitment,
             _refundCommitment,
+            _claimer,
             swap.timeout1,
             swap.timeout2,
             swap.asset,
-            swap.value
+            swap.value,
+            swap.nonce
         );
         swaps[swapID] = Stage.PENDING;
         return swapID;

+ 2 - 0
src/darkfi/error.rs

@@ -30,4 +30,6 @@ pub enum Error {
     ReadyEventStreamFailed,
     #[error("listening to Refunded event stream failed")]
     RefundedEventStreamFailed,
+    #[error("middleware error: {0}")]
+    MiddlewareError(String),
 }

+ 16 - 13
src/darkfi/follower.rs

@@ -1,15 +1,18 @@
 use crate::protocol::traits::FollowerArgs;
 use darkfi_sdk::crypto::{Keypair, SecretKey};
-use darkfi_serial::async_trait;
 
 use super::{wallet::Wallet, Error};
-use crate::protocol::traits::Follower;
+use crate::protocol::traits::{ContractSwapArgs, Follower};
 
 /// Implemented on top of the non-initiating chain
 ///
 /// Can probably become an extension trait of an RPC client eventually
 pub(crate) trait OtherChainClient {
-    fn claim_funds(&self, our_secret: [u8; 32]) -> Result<(), crate::Error>;
+    fn claim_funds(
+        &self,
+        our_secret: [u8; 32],
+        contract_swap_args: ContractSwapArgs,
+    ) -> Result<(), crate::Error>;
 }
 
 pub(crate) struct DrkFollower<C: OtherChainClient> {
@@ -17,29 +20,26 @@ pub(crate) struct DrkFollower<C: OtherChainClient> {
     secret: SecretKey,
     wallet: Wallet,
     args: FollowerArgs,
+    contract_swap_args: Option<ContractSwapArgs>,
 }
 
 impl<C: OtherChainClient> DrkFollower<C> {
     fn new(other_chain_client: C, secret: SecretKey, wallet: Wallet, args: FollowerArgs) -> Self {
-        Self { other_chain_client, secret, wallet, args }
+        Self { other_chain_client, secret, wallet, args, contract_swap_args: None }
     }
 }
 
 impl<C: OtherChainClient + Send + Sync> Follower for DrkFollower<C> {
     // handle the swap initiation by locking funds on chain B
     fn handle_counterparty_funds_locked(
-        &self,
-        contract_swap_id: [u8; 32],
+        &mut self,
+        contract_swap_args: ContractSwapArgs,
     ) -> Result<(), crate::Error> {
+        self.contract_swap_args = Some(contract_swap_args);
+
         // lock DRK funds to shared swap account
         let shared_swap_public_key = Keypair::new(self.secret).public;
 
-        // TODO: ensure that the funds locked have the correct parameters before locking:
-        // - value
-        // - asset
-        // - commitment to our pubkey
-        // - timeouts
-
         // cursed hack b/c `exec_sql` takes `dyn ToSql` which is not Send or Sync :/
         let tx = async_std::task::block_on(
             self.wallet.build_swap_transfer(self.args.value, shared_swap_public_key),
@@ -59,7 +59,10 @@ impl<C: OtherChainClient + Send + Sync> Follower for DrkFollower<C> {
             .as_ref()
             .try_into()
             .expect("can convert secret key to 32 byte representation");
-        self.other_chain_client.claim_funds(our_secret)?;
+        self.other_chain_client.claim_funds(
+            our_secret,
+            self.contract_swap_args.as_ref().expect("`contract_swap_id` must be set").clone(),
+        )?;
         Ok(())
     }
 

+ 22 - 12
src/darkfi/follower_event_watcher.rs

@@ -1,15 +1,11 @@
-use std::time::{SystemTime, UNIX_EPOCH};
-
 use crate::{
     darkfi::Error,
-    ethereum::swap_creator::SwapCreator,
-    protocol::{
-        follower::Event,
-        traits::{CounterpartyKeys, FollowerEventWatcher},
-    },
+    ethereum::{swap_creator::SwapCreator, utils},
+    protocol::{follower::Event, traits::FollowerEventWatcher},
 };
 use ethers::prelude::Middleware;
 use smol::{channel, stream::StreamExt as _};
+use std::sync::Arc;
 
 pub(crate) struct Watcher;
 
@@ -18,13 +14,13 @@ impl FollowerEventWatcher for Watcher {
     async fn run_counterparty_funds_locked_watcher<M: Middleware>(
         event_tx: channel::Sender<Event>,
         contract: SwapCreator<M>,
+        middleware: Arc<M>,
         claim_commitment: [u8; 32],
         refund_commitment: [u8; 32],
         from_block: u64,
     ) -> Result<(), crate::Error> {
         // watch for a `NewSwap` event with the correct swap parameters
-        // note: we still need to check for correct asset, value, and timeout,
-        // which is done in the event handler [`Follower`].
+        // note: we still need to check for correct asset, value, and timeout.
         let topic2: ethers::types::U256 = claim_commitment.into();
         let topic3: ethers::types::U256 = refund_commitment.into();
         let events = contract
@@ -34,16 +30,30 @@ impl FollowerEventWatcher for Watcher {
             .topic2(topic2) // `newSwap` event sig is topic0 and `contract_swap_id` is topic1
             .topic3(topic3);
 
+        // TODO: ensure that the funds locked have the correct parameters before locking:
+        // - value
+        // - asset
+        // - timeouts
+
         let mut stream = events.stream().await.unwrap().with_meta();
 
         // we listen for the first event, as there can only be one event
         // that matches the filter (ie. has the same swap_id)
-        let Some(Ok((event, _meta))) = stream.next().await else {
+        let Some(Ok((_event, meta))) = stream.next().await else {
             return Err(Error::ReadyEventStreamFailed.into());
         };
 
-        let contract_swap_id = event.swap_id;
-        event_tx.send(Event::CounterpartyFundsLocked(contract_swap_id)).await.unwrap();
+        let receipt = middleware
+            .get_transaction_receipt(meta.transaction_hash)
+            .await
+            .map_err(|e| {
+                Error::MiddlewareError(format!("failed to get transaction receipt: {:?}", e))
+            })?
+            .expect("receipt must exist if log exists");
+
+        let (contract_swap, _) = utils::parse_new_swap_event_from_receipt(receipt)?;
+
+        event_tx.send(Event::CounterpartyFundsLocked(contract_swap)).await.unwrap();
         Ok(())
     }
 

+ 1 - 1
src/darkfi/wallet.rs

@@ -26,7 +26,7 @@ impl Wallet {
         endpoint: Url,
         ex: Arc<smol::Executor<'static>>,
     ) -> Result<Self, crate::Error> {
-        let drk = Drk::new(wallet_path, wallet_pass, endpoint, ex)
+        let drk = Drk::new(wallet_path, wallet_pass, Some(endpoint), ex)
             .await
             .map_err(|e| crate::Error::from(Error::DrkInitializationFailed(e)))?;
         drk.initialize_wallet()

+ 4 - 0
src/ethereum/error.rs

@@ -34,4 +34,8 @@ pub enum Error {
     ExpectedFixedBytes(ethers::abi::Token),
     #[error("expected two U256s, got something else")]
     ExpectedTwoU256s,
+    #[error("expected address, got another token type: {0}")]
+    ExpectedAddress(ethers::abi::Token),
+    #[error("expected U256, got another token type: {0}")]
+    ExpectedU256(ethers::abi::Token),
 }

+ 15 - 94
src/ethereum/initiator.rs

@@ -1,16 +1,12 @@
 use crate::{
-    ethereum::{
-        swap_creator::{Swap, SwapCreator},
-        Error,
-    },
-    protocol::traits::{HandleCounterpartyKeysReceivedResult, InitiateSwapArgs, Initiator},
+    ethereum::{swap_creator::SwapCreator, utils, Error},
+    protocol::traits::{ContractSwapArgs, HandleCounterpartyKeysReceivedResult, Initiator},
 };
 
 use darkfi_serial::async_trait;
 use ethers::prelude::*;
 
 use log::info;
-use std::sync::Arc;
 
 /// Implemented on top of the non-initiating chain
 ///
@@ -25,20 +21,14 @@ pub(crate) trait OtherChainClient {
 
 pub(crate) struct EthInitiator<M: Middleware, C: OtherChainClient> {
     contract: SwapCreator<M>,
-    middleware: Arc<M>,
     other_chain_client: C,
     secret: [u8; 32],
 }
 
 #[allow(dead_code)]
 impl<M: Middleware, C: OtherChainClient> EthInitiator<M, C> {
-    pub(crate) fn new(
-        contract: SwapCreator<M>,
-        middleware: Arc<M>,
-        other_chain_client: C,
-        secret: [u8; 32],
-    ) -> Self {
-        Self { contract, middleware, other_chain_client, secret }
+    pub(crate) fn new(contract: SwapCreator<M>, other_chain_client: C, secret: [u8; 32]) -> Self {
+        Self { contract, other_chain_client, secret }
     }
 }
 
@@ -46,19 +36,18 @@ impl<M: Middleware, C: OtherChainClient> EthInitiator<M, C> {
 impl<M: Middleware + 'static, C: OtherChainClient + Send + Sync> Initiator for EthInitiator<M, C> {
     async fn handle_counterparty_keys_received(
         &self,
-        args: InitiateSwapArgs,
+        args: ContractSwapArgs,
     ) -> Result<HandleCounterpartyKeysReceivedResult, crate::Error> {
-        use ethers::abi::ParamType;
-
-        let InitiateSwapArgs {
+        let ContractSwapArgs {
             claim_commitment,
             refund_commitment,
             claimer,
-            timeout_duration_1,
-            timeout_duration_2,
+            timeout_1,
+            timeout_2,
             asset,
             value,
             nonce,
+            ..
         } = args;
 
         // TODO: ERC20 is *not* handled right now
@@ -72,8 +61,8 @@ impl<M: Middleware + 'static, C: OtherChainClient + Send + Sync> Initiator for E
                 claim_commitment,
                 refund_commitment,
                 claimer,
-                timeout_duration_1,
-                timeout_duration_2,
+                timeout_1,
+                timeout_2,
                 asset,
                 value,
                 nonce,
@@ -87,74 +76,9 @@ impl<M: Middleware + 'static, C: OtherChainClient + Send + Sync> Initiator for E
             .map_err(|e| Error::FailedToAwaitPendingTransaction("new_swap".to_string(), e))?
             .ok_or_else(|| Error::NoReceipt)?;
 
-        if receipt.status != Some(U64::from(1)) {
-            return Err(Error::TransactionFailed("new_swap".to_string(), receipt).into());
-        }
-
-        if receipt.logs.len() != 1 {
-            return Err(Error::NewSwapUnexpectedLogCount(receipt.logs.len()).into());
-        }
-
-        if receipt.logs[0].topics.len() != 1 {
-            return Err(Error::NewSwapUnexpectedTopicCount(receipt.logs[0].topics.len()).into());
-        }
-
-        let log_data = &receipt.logs[0].data;
-
-        // ABI-unpack log data
-        // note: there are other parameters emitted in the log, but we don't care about them
-        let mut tokens = ethers::abi::decode(
-            &vec![
-                ParamType::FixedBytes(32),
-                ParamType::FixedBytes(32),
-                ParamType::FixedBytes(32),
-                ParamType::Uint(256),
-                ParamType::Uint(256),
-            ],
-            &log_data.0,
-        )
-        .map_err(|e| Error::NewSwapLogDecodingFailed(e))?;
-
-        if tokens.len() != 5 {
-            return Err(Error::NewSwapUnexpectedLogTokenCount(tokens.len()).into());
-        }
-
-        let swap_id = match tokens.remove(0) {
-            ethers::abi::Token::FixedBytes(bytes) => {
-                // this shouldn't happen, would be an error in ethers-rs
-                if bytes.len() != 32 {
-                    return Err(Error::FixedBytesDecodingError(bytes.len()).into());
-                }
-
-                let mut swap_id = [0u8; 32];
-                swap_id.copy_from_slice(&bytes);
-                swap_id
-            }
-            token => {
-                return Err(Error::ExpectedFixedBytes(token).into());
-            }
-        };
-        let (timeout_1, timeout_2) = match (tokens.remove(2), tokens.remove(2)) {
-            // tokens index 3 and 4
-            (ethers::abi::Token::Uint(timeout_1), ethers::abi::Token::Uint(timeout_2)) => {
-                (timeout_1, timeout_2)
-            }
-            _ => {
-                return Err(Error::ExpectedTwoU256s.into());
-            }
-        };
-
-        let contract_swap = Swap {
-            owner: self.middleware.default_sender().expect("must have a default sender"),
-            claim_commitment,
-            refund_commitment,
-            claimer,
-            timeout_1,
-            timeout_2,
-            asset,
-            value,
-            nonce,
-        };
+        let block_number =
+            receipt.block_number.expect("block number must be set in receipt").as_u64();
+        let (contract_swap, swap_id) = utils::parse_new_swap_event_from_receipt(receipt)?;
 
         info!(
             "initiated swap on-chain: contract_swap_id = {}",
@@ -164,10 +88,7 @@ impl<M: Middleware + 'static, C: OtherChainClient + Send + Sync> Initiator for E
         Ok(HandleCounterpartyKeysReceivedResult {
             contract_swap_id: swap_id,
             contract_swap,
-            block_number: receipt
-                .block_number
-                .expect("block number must be set in receipt")
-                .as_u64(),
+            block_number,
         })
     }
 

+ 1 - 0
src/ethereum/mod.rs

@@ -2,6 +2,7 @@ mod error;
 pub(crate) mod initiator;
 mod initiator_event_watcher;
 pub(crate) mod swap_creator;
+pub(crate) mod utils;
 
 pub use error::Error;
 #[allow(unused_imports)]

+ 1 - 1
src/ethereum/swap_creator.rs

@@ -1,3 +1,3 @@
 use ethers::prelude::*;
 
-abigen!(SwapCreator, "./ethereum/out/SwapCreator.sol/SwapCreator.json",);
+abigen!(SwapCreator, "./ethereum/out/SwapCreator.sol/SwapCreator.json");

+ 143 - 0
src/ethereum/utils.rs

@@ -0,0 +1,143 @@
+use crate::ethereum::{error::Error, swap_creator::Swap};
+use ethers::{
+    abi::{Address, ParamType},
+    types::{TransactionReceipt, U64},
+};
+
+/// Parse a `newSwap` event from a transaction receipt.
+///
+/// Returns the `Swap` struct and the swap ID.
+pub(crate) fn parse_new_swap_event_from_receipt(
+    receipt: TransactionReceipt,
+) -> Result<(Swap, [u8; 32]), crate::Error> {
+    if receipt.status != Some(U64::from(1)) {
+        return Err(Error::TransactionFailed("new_swap".to_string(), receipt).into());
+    }
+
+    if receipt.logs.len() != 1 {
+        return Err(Error::NewSwapUnexpectedLogCount(receipt.logs.len()).into());
+    }
+
+    if receipt.logs[0].topics.len() != 1 {
+        return Err(Error::NewSwapUnexpectedTopicCount(receipt.logs[0].topics.len()).into());
+    }
+
+    let log_data = &receipt.logs[0].data;
+
+    // ABI-unpack log data
+    // note: there are other parameters emitted in the log, but we don't care about them
+    let mut tokens = ethers::abi::decode(
+        &vec![
+            ParamType::FixedBytes(32), // swapID
+            ParamType::FixedBytes(32), // claimKey
+            ParamType::FixedBytes(32), // refundKey
+            ParamType::Address,        // claimer
+            ParamType::Uint(256),      // timeout_1
+            ParamType::Uint(256),      // timeout_2
+            ParamType::Address,        // asset
+            ParamType::Uint(256),      // value
+            ParamType::Uint(256),      // nonce
+        ],
+        &log_data.0,
+    )
+    .map_err(|e| Error::NewSwapLogDecodingFailed(e))?;
+
+    if tokens.len() != 9 {
+        return Err(Error::NewSwapUnexpectedLogTokenCount(tokens.len()).into());
+    }
+
+    let swap_id = match tokens.remove(0) {
+        ethers::abi::Token::FixedBytes(bytes) => {
+            // this shouldn't happen, would be an error in ethers-rs
+            if bytes.len() != 32 {
+                return Err(Error::FixedBytesDecodingError(bytes.len()).into());
+            }
+
+            let mut swap_id = [0u8; 32];
+            swap_id.copy_from_slice(&bytes);
+            swap_id
+        }
+        token => {
+            return Err(Error::ExpectedFixedBytes(token).into());
+        }
+    };
+    let claim_commitment = match tokens.remove(0) {
+        ethers::abi::Token::FixedBytes(bytes) => {
+            if bytes.len() != 32 {
+                return Err(Error::FixedBytesDecodingError(bytes.len()).into());
+            }
+
+            let mut claim_commitment = [0u8; 32];
+            claim_commitment.copy_from_slice(&bytes);
+            claim_commitment
+        }
+        token => {
+            return Err(Error::ExpectedFixedBytes(token).into());
+        }
+    };
+    let refund_commitment = match tokens.remove(0) {
+        ethers::abi::Token::FixedBytes(bytes) => {
+            if bytes.len() != 32 {
+                return Err(Error::FixedBytesDecodingError(bytes.len()).into());
+            }
+
+            let mut refund_commitment = [0u8; 32];
+            refund_commitment.copy_from_slice(&bytes);
+            refund_commitment
+        }
+        token => {
+            return Err(Error::ExpectedFixedBytes(token).into());
+        }
+    };
+
+    let claimer: Address = match tokens.remove(0) {
+        ethers::abi::Token::Address(bytes) => bytes.into(),
+        token => {
+            return Err(Error::ExpectedAddress(token).into());
+        }
+    };
+
+    let (timeout_1, timeout_2) = match (tokens.remove(0), tokens.remove(0)) {
+        // tokens index 3 and 4
+        (ethers::abi::Token::Uint(timeout_1), ethers::abi::Token::Uint(timeout_2)) => {
+            (timeout_1, timeout_2)
+        }
+        _ => {
+            return Err(Error::ExpectedTwoU256s.into());
+        }
+    };
+
+    let asset: Address = match tokens.remove(0) {
+        ethers::abi::Token::Address(bytes) => bytes.into(),
+        token => {
+            return Err(Error::ExpectedAddress(token).into());
+        }
+    };
+
+    let value = match tokens.remove(0) {
+        ethers::abi::Token::Uint(value) => value,
+        token => {
+            return Err(Error::ExpectedU256(token).into());
+        }
+    };
+
+    let nonce = match tokens.remove(0) {
+        ethers::abi::Token::Uint(nonce) => nonce,
+        token => {
+            return Err(Error::ExpectedU256(token).into());
+        }
+    };
+
+    let contract_swap = Swap {
+        owner: receipt.from,
+        claim_commitment,
+        refund_commitment,
+        claimer,
+        timeout_1,
+        timeout_2,
+        asset,
+        value,
+        nonce,
+    };
+    Ok((contract_swap, swap_id))
+}

+ 4 - 4
src/protocol/follower.rs

@@ -1,4 +1,4 @@
-use super::Error;
+use super::{traits::ContractSwapArgs, Error};
 use crate::protocol::traits::Follower;
 use smol::channel;
 
@@ -8,7 +8,7 @@ use log::{info, warn};
 pub(crate) enum Event {
     // occurs when the counterparty has locked funds in the contract.
     // contains the swap id within the contract.
-    CounterpartyFundsLocked([u8; 32]),
+    CounterpartyFundsLocked(ContractSwapArgs),
     ReadyToClaim,
     CounterpartyFundsRefunded([u8; 32]),
 }
@@ -48,7 +48,7 @@ impl Swap {
     async fn run(&mut self) -> Result<(), crate::Error> {
         loop {
             match self.event_rx.recv().await {
-                Ok(Event::CounterpartyFundsLocked(contract_swap_id)) => {
+                Ok(Event::CounterpartyFundsLocked(contract_swap_args)) => {
                     info!("counterparty funds locked");
 
                     if !matches!(*self.state_rx.borrow(), State::WaitingForCounterpartyFundsLocked)
@@ -60,7 +60,7 @@ impl Swap {
                         return Err(Error::UnexpectedCounterpartyFundsLocked.into());
                     }
 
-                    self.handler.handle_counterparty_funds_locked(contract_swap_id)?;
+                    self.handler.handle_counterparty_funds_locked(contract_swap_args)?;
 
                     self.state_tx
                         .send(State::WaitingForContractReady)

+ 10 - 9
src/protocol/initiator.rs

@@ -1,6 +1,6 @@
 use crate::protocol::{
     traits::{
-        CounterpartyKeys, HandleCounterpartyKeysReceivedResult, InitiateSwapArgs, InitiationArgs,
+        ContractSwapArgs, CounterpartyKeys, HandleCounterpartyKeysReceivedResult, InitiationArgs,
         Initiator,
     },
     Error,
@@ -96,12 +96,13 @@ impl Swap {
                     let refund_commitment =
                         ethers::utils::keccak256(&counterparty_keys.secp256k1_public_key);
 
-                    let args = InitiateSwapArgs {
+                    let args = ContractSwapArgs {
+                        owner: self.args.owner,
+                        claimer: self.args.claimer,
                         claim_commitment: self.args.claim_commitment,
                         refund_commitment,
-                        claimer: self.args.claimer,
-                        timeout_duration_1: self.args.timeout_duration_1,
-                        timeout_duration_2: self.args.timeout_duration_2,
+                        timeout_1: self.args.timeout_duration_1,
+                        timeout_2: self.args.timeout_duration_2,
                         asset: self.args.asset,
                         value: self.args.value,
                         nonce: self.args.nonce,
@@ -220,7 +221,6 @@ impl Swap {
 #[cfg(test)]
 mod test {
     use super::*;
-
     use std::sync::Arc;
 
     use smol::channel::bounded;
@@ -259,8 +259,7 @@ mod test {
 
         let other_chain_client = MockOtherChainClient;
         let refund_secret = [0; 32]; // TODO generate an actual secp256k1 private key for refund testing
-        let initiator =
-            EthInitiator::new(contract.clone(), signer.clone(), other_chain_client, refund_secret);
+        let initiator = EthInitiator::new(contract.clone(), other_chain_client, refund_secret);
 
         // TODO: this is the same key as the initiator right now.
         let counterparty_secret: [u8; 32] = anvil.keys()[0].to_bytes().try_into().unwrap();
@@ -270,6 +269,7 @@ mod test {
         let claim_commitment = ethers::utils::keccak256(pubkey_bytes);
 
         let args = InitiationArgs {
+            owner: signer.address(),
             claim_commitment,
             claimer: signer.address(),
             timeout_duration_1: U256::from(120),
@@ -295,9 +295,10 @@ mod test {
             .send(CounterpartyKeys { secp256k1_public_key: [0; 33] })
             .await
             .expect("should send counterparty keys");
+        smol::future::block_on(join_handle)
+            .expect("run_received_counterparty_keys_watcher should finish");
         state.changed().await.expect("state should change");
         assert!(*state.borrow() == State::WaitingForCounterpartyFundsLocked);
-        join_handle.cancel().await.unwrap().unwrap();
 
         Watcher::run_counterparty_funds_locked_watcher(event_tx.clone())
             .await

+ 37 - 16
src/protocol/traits.rs

@@ -13,26 +13,16 @@ use std::{
     fmt::{Display, Formatter},
 };
 
+pub(crate) use crate::ethereum::swap_creator::Swap as ContractSwapArgs;
+
 // Initial parameters required by the swap initiator.
 // TODO: make Address/U256 generic; these are ethers-specific right now
 #[allow(dead_code)]
 #[derive(Debug, Clone)]
 pub(crate) struct InitiationArgs {
-    pub(crate) claim_commitment: [u8; 32],
+    pub(crate) owner: Address,
     pub(crate) claimer: Address,
-    pub(crate) timeout_duration_1: U256,
-    pub(crate) timeout_duration_2: U256,
-    pub(crate) asset: Address,
-    pub(crate) value: U256,
-    pub(crate) nonce: U256,
-}
-
-// TODO: make Address/U256 generic; these are ethers-specific right now
-#[derive(Debug)]
-pub(crate) struct InitiateSwapArgs {
     pub(crate) claim_commitment: [u8; 32],
-    pub(crate) refund_commitment: [u8; 32],
-    pub(crate) claimer: Address,
     pub(crate) timeout_duration_1: U256,
     pub(crate) timeout_duration_2: U256,
     pub(crate) asset: Address,
@@ -40,6 +30,36 @@ pub(crate) struct InitiateSwapArgs {
     pub(crate) nonce: U256,
 }
 
+// // TODO: make Address/U256 generic; these are ethers-specific right now
+// #[derive(Debug, Clone)]
+// pub(crate) struct ContractSwapArgs {
+//     pub(crate) owner: Address,
+//     pub(crate) claimer: Address,
+//     pub(crate) claim_commitment: [u8; 32],
+//     pub(crate) refund_commitment: [u8; 32],
+//     pub(crate) timeout_duration_1: U256,
+//     pub(crate) timeout_duration_2: U256,
+//     pub(crate) asset: Address,
+//     pub(crate) value: U256,
+//     pub(crate) nonce: U256,
+// }
+
+// impl From<ContractSwapArgs> for crate::ethereum::swap_creator::Swap {
+//     fn from(args: ContractSwapArgs) -> Self {
+//         Self {
+//             owner: args.owner,
+//             claim_commitment: args.claim_commitment,
+//             refund_commitment: args.refund_commitment,
+//             claimer: args.claimer,
+//             timeout_1: args.timeout_duration_1,
+//             timeout_2: args.timeout_duration_2,
+//             asset: args.asset,
+//             value: args.value,
+//             nonce: args.nonce,
+//         }
+//     }
+// }
+
 // Initial parameters required by the swap follower.
 #[derive(Debug)]
 pub(crate) struct FollowerArgs {
@@ -88,7 +108,7 @@ pub(crate) trait Initiator {
     // initiates the swap by locking funds on chain A
     async fn handle_counterparty_keys_received(
         &self,
-        args: InitiateSwapArgs,
+        args: ContractSwapArgs,
     ) -> Result<HandleCounterpartyKeysReceivedResult, Error>;
 
     // handles the counterparty locking funds
@@ -143,8 +163,8 @@ pub(crate) trait InitiatorEventWatcher {
 pub(crate) trait Follower {
     // handle the swap initiation by locking funds on chain B
     fn handle_counterparty_funds_locked(
-        &self,
-        contract_swap_id: [u8; 32],
+        &mut self,
+        contract_swap_id: ContractSwapArgs,
     ) -> Result<(), crate::Error>;
 
     // handle the funds being ready to be claimed by us
@@ -162,6 +182,7 @@ pub(crate) trait FollowerEventWatcher {
     async fn run_counterparty_funds_locked_watcher<M: Middleware>(
         event_tx: channel::Sender<follower::Event>,
         contract: SwapCreator<M>,
+        middleware: std::sync::Arc<M>,
         claim_commitment: [u8; 32],
         refund_commitment: [u8; 32],
         from_block: u64,