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
use std::str::FromStr;

use bridge_e2e_traits::strategy::RelayStrategy;

use secp256k1::SecretKey;
use support_common::error::BridgerError;
use thegraph_liketh::graph::TheGraphLikeEth;
use web3::{
    contract::Options,
    transports::Http,
    types::{Address, BlockId, BlockNumber},
    Web3,
};

use client_contracts::{
    inbound_types::ReceiveMessagesProof, outbound_types::ReceiveMessagesDeliveryProof,
    ChainMessageCommitter, Inbound, LaneMessageCommitter,
};
use client_contracts::{FeeMarket, Outbound};

use super::{
    fee_market::FeeMarketRelayStrategy,
    utils::{
        build_darwinia_confirmation_proof, build_darwinia_delivery_proof, build_messages_data,
    },
};

pub struct DarwiniaMessageClient<T: RelayStrategy> {
    pub client: Web3<Http>,
    pub inbound: Inbound,
    pub outbound: Outbound,
    pub chain_message_committer: ChainMessageCommitter,
    pub lane_message_committer: LaneMessageCommitter,
    pub strategy: T,
    pub private_key: Option<SecretKey>,
    pub indexer: TheGraphLikeEth,
    pub gas_option: Options,
}

#[allow(clippy::too_many_arguments)]
pub fn build_darwinia_message_client(
    endpoint: &str,
    inbound_address: Address,
    outbound_address: Address,
    chain_message_committer_address: Address,
    lane_message_committer_address: Address,
    fee_market_address: Address,
    account: Address,
    private_key: Option<&str>,
    indexer: TheGraphLikeEth,
    gas_option: Options,
) -> color_eyre::Result<DarwiniaMessageClient<FeeMarketRelayStrategy>> {
    let transport = Http::new(endpoint)?;
    let client = Web3::new(transport);
    let inbound = Inbound::new(&client, inbound_address)?;
    let outbound = Outbound::new(&client, outbound_address)?;
    let fee_market = FeeMarket::new(&client, fee_market_address)?;
    let strategy = FeeMarketRelayStrategy::new(fee_market, account);
    let chain_message_committer =
        ChainMessageCommitter::new(&client, chain_message_committer_address)?;
    let lane_message_committer =
        LaneMessageCommitter::new(&client, lane_message_committer_address)?;
    let private_key = private_key.map(SecretKey::from_str).transpose()?;
    Ok(DarwiniaMessageClient {
        client,
        inbound,
        outbound,
        chain_message_committer,
        lane_message_committer,
        strategy,
        private_key,
        indexer,
        gas_option,
    })
}

impl<T: RelayStrategy> DarwiniaMessageClient<T> {
    pub fn private_key(&self) -> color_eyre::Result<SecretKey> {
        Ok(self
            .private_key
            .ok_or_else(|| BridgerError::Custom("Private key not found!".into()))?)
    }

    pub async fn prepare_for_messages_confirmation(
        &self,
        block_id: Option<BlockId>,
    ) -> color_eyre::Result<ReceiveMessagesDeliveryProof> {
        let inbound_lane_data = self.inbound.data(block_id).await?;
        let messages_proof = build_darwinia_confirmation_proof(
            &self.inbound,
            &self.lane_message_committer,
            &self.chain_message_committer,
            block_id,
        )
        .await?;
        Ok(ReceiveMessagesDeliveryProof {
            inbound_lane_data,
            messages_proof,
        })
    }

    pub async fn prepare_for_messages_delivery(
        &self,
        begin: u64,
        end: u64,
        block_number: Option<BlockNumber>,
    ) -> color_eyre::Result<ReceiveMessagesProof> {
        let outbound_lane_data =
            build_messages_data(&self.indexer, &self.outbound, begin, end, block_number).await?;
        let messages_proof = build_darwinia_delivery_proof(
            &self.outbound,
            &self.lane_message_committer,
            &self.chain_message_committer,
            block_number.map(BlockId::from),
        )
        .await?;

        Ok(ReceiveMessagesProof {
            outbound_lane_data,
            messages_proof,
        })
    }
}