1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use crate::primitives::*;
use async_trait::async_trait;
use primitives::{ChainId, ChainOf, Channel};
use std::{marker::PhantomData, sync::Arc};

use crate::{
    client::{Locked, Unlockable, Unlocked},
    Error,
};

pub(crate) mod state {
    #[derive(Debug, Clone, Copy)]
    /// The `Locked` state of the [`crate::Adapter`].
    /// See [`crate::client::Locked`]
    pub struct LockedState;

    /// The `Unlocked` state of the [`crate::Adapter`].
    /// See [`crate::client::Unlocked`]
    #[derive(Debug, Clone, Copy)]
    pub struct UnlockedState;
}

#[derive(Debug)]
/// The [`Adapter`] struct and it's states.
///
/// Used for communication with the underlying client implementation.
///
/// # Available adapters
///
/// 2 Adapters are available in this crate:
/// - Ethereum
///   - [`crate::ethereum::LockedAdapter`] and [`crate::ethereum::UnlockedAdapter`]
///   - Client implementation [`crate::Ethereum`] for chains compatible with EVM.
/// - Dummy
///   - [`crate::dummy::Adapter`] and it's client implementation [`crate::Dummy`] for testing.
pub struct Adapter<C, S = state::LockedState> {
    /// client in a specific state - Locked or Unlocked
    pub client: Arc<C>,
    _state: PhantomData<S>,
}

impl<C, S: Clone> Clone for Adapter<C, S> {
    fn clone(&self) -> Self {
        Self {
            client: self.client.clone(),
            _state: self._state,
        }
    }
}

impl<C: Locked> Adapter<C> {
    /// Create a new [`Adapter`] in [`Locked`] state using a [`Locked`].
    pub fn new(client: C) -> Adapter<C, state::LockedState> {
        Adapter {
            client: Arc::new(client),
            _state: PhantomData::default(),
        }
    }
}

impl<C: Unlocked> Adapter<C, state::LockedState> {
    /// Create a new [`Adapter`] in [`state::UnlockedState`] state using an [`Unlocked`] client.
    pub fn with_unlocked(client: C) -> Adapter<C, state::UnlockedState> {
        Adapter {
            client: Arc::new(client),
            _state: PhantomData::default(),
        }
    }
}

impl<C> Adapter<C, state::LockedState>
where
    C: Locked + Unlockable,
    <C::Unlocked as Locked>::Error: Into<Error>,
    C::Error: Into<Error>,
{
    pub fn unlock(self) -> Result<Adapter<C::Unlocked, state::UnlockedState>, Error> {
        let unlocked = self.client.unlock().map_err(Into::into)?;

        Ok(Adapter {
            client: Arc::new(unlocked),
            _state: PhantomData::default(),
        })
    }
}

#[async_trait]
impl<C> Unlocked for Adapter<C, state::UnlockedState>
where
    C: Unlocked + Sync + Send,
    C::Error: Into<Error>,
{
    fn sign(&self, state_root: &str) -> Result<String, Error> {
        self.client.sign(state_root).map_err(Into::into)
    }

    fn get_auth(&self, for_chain: ChainId, intended_for: ValidatorId) -> Result<String, Error> {
        self.client
            .get_auth(for_chain, intended_for)
            .map_err(Into::into)
    }
}

#[async_trait]
impl<C, S> Locked for Adapter<C, S>
where
    C: Locked + Sync + Send,
    C::Error: Into<Error>,
    S: Sync + Send,
{
    type Error = Error;
    /// Get Adapter whoami
    fn whoami(&self) -> ValidatorId {
        self.client.whoami()
    }

    /// Verify, based on the signature & state_root, that the signer is the same
    fn verify(
        &self,
        signer: ValidatorId,
        state_root: &str,
        signature: &str,
    ) -> Result<bool, Error> {
        self.client
            .verify(signer, state_root, signature)
            .map_err(Into::into)
    }

    /// Creates a `Session` from a provided Token by calling the Contract.
    /// Does **not** cache the (`Token`, [`Session`]) pair.
    async fn session_from_token(&self, token: &str) -> Result<Session, Error> {
        self.client
            .session_from_token(token)
            .await
            .map_err(Into::into)
    }

    async fn get_deposit(
        &self,
        channel_context: &ChainOf<Channel>,
        depositor_address: Address,
    ) -> Result<Deposit, Error> {
        self.client
            .get_deposit(channel_context, depositor_address)
            .await
            .map_err(Into::into)
    }
}