|
|
@@ -0,0 +1,85 @@
|
|
|
+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;
|
|
|
+
|
|
|
+/// 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>;
|
|
|
+}
|
|
|
+
|
|
|
+pub(crate) struct DrkFollower<C: OtherChainClient> {
|
|
|
+ other_chain_client: C,
|
|
|
+ secret: SecretKey,
|
|
|
+ wallet: Wallet,
|
|
|
+ args: FollowerArgs,
|
|
|
+}
|
|
|
+
|
|
|
+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 }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+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) -> Result<(), crate::Error> {
|
|
|
+ // 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),
|
|
|
+ )?;
|
|
|
+ let _tx_hash = async_std::task::block_on(self.wallet.submit_transaction(&tx))?;
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+
|
|
|
+ // handle the funds being ready to be claimed by us
|
|
|
+ fn handle_ready_to_claim(&self) -> Result<(), crate::Error> {
|
|
|
+ use darkfi_sdk::crypto::pasta_prelude::PrimeField as _;
|
|
|
+
|
|
|
+ let our_secret: [u8; 32] = self
|
|
|
+ .secret
|
|
|
+ .inner()
|
|
|
+ .to_repr()
|
|
|
+ .as_ref()
|
|
|
+ .try_into()
|
|
|
+ .expect("can convert secret key to 32 byte representation");
|
|
|
+ self.other_chain_client.claim_funds(our_secret)?;
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+
|
|
|
+ // handle the counterparty refunding their funds, in case of a timeout
|
|
|
+ fn handle_counterparty_funds_refunded(
|
|
|
+ &self,
|
|
|
+ counterparty_secret: [u8; 32],
|
|
|
+ ) -> Result<(), crate::Error> {
|
|
|
+ let counterparty_secret_key = SecretKey::from_bytes(counterparty_secret)
|
|
|
+ .map_err(|e| crate::Error::from(Error::CounterpartySecretKeyConversionFailed(e)))?;
|
|
|
+ let counterparty_secret_fp = counterparty_secret_key.inner();
|
|
|
+ let our_secret_fp = self.secret.inner();
|
|
|
+ let shared_secret_fp = counterparty_secret_fp + our_secret_fp;
|
|
|
+ let shared_secret = SecretKey::from(shared_secret_fp);
|
|
|
+ let keypair = Keypair::new(shared_secret);
|
|
|
+
|
|
|
+ async_std::task::block_on(self.wallet.put_keypair(keypair))?;
|
|
|
+ let tx = async_std::task::block_on(self.wallet.build_transfer(
|
|
|
+ self.args.value,
|
|
|
+ self.wallet.user_keypair().public,
|
|
|
+ keypair,
|
|
|
+ ))?;
|
|
|
+ let _tx_hash = async_std::task::block_on(self.wallet.submit_transaction(&tx))?;
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+}
|