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
use std::str::FromStr;
use crate::pangoro_client::types::{BSCHeader, Checkpoint, TBSCHeader};
use secp256k1::SecretKey;
use support_common::error::BridgerError;
use web3::{
contract::{tokens::Tokenize, Contract, Options},
ethabi::Token,
transports::Http,
types::{Address, H256, U256},
Web3,
};
pub struct PangoroClient {
pub client: Web3<Http>,
pub bsc_light_client: Contract<Http>,
pub private_key: Option<SecretKey>,
}
impl PangoroClient {
pub fn new(
endpoint: &str,
bsc_address: &str,
private_key: Option<&str>,
) -> color_eyre::Result<Self> {
let transport = Http::new(endpoint)?;
let client = Web3::new(transport);
let bsc_light_client = Contract::from_json(
client.eth(),
Address::from_str(bsc_address)?,
include_bytes!("BSCLightClient.json"),
)?;
let private_key = private_key
.map(SecretKey::from_str)
.transpose()?;
Ok(Self {
client,
bsc_light_client,
private_key,
})
}
pub async fn get_finalized_checkpoint(&self) -> color_eyre::Result<Checkpoint> {
let query =
self.bsc_light_client
.query("finalized_checkpoint", (), None, Options::default(), None);
let checkpoint: Checkpoint = query.await?;
Ok(checkpoint)
}
pub async fn get_authority_set_length(&self) -> color_eyre::Result<U256> {
let query = self.bsc_light_client.query(
"length_of_finalized_authorities",
(),
None,
Options::default(),
None,
);
let length: U256 = query.await?;
Ok(length)
}
pub async fn import_finalized_epoch_header(
&self,
headers: Vec<BSCHeader>,
) -> color_eyre::Result<H256> {
let parameter = headers
.into_iter()
.map(|x| Token::Tuple(TBSCHeader::from(x).into_tokens()))
.collect::<Vec<Token>>();
let tx = self
.bsc_light_client
.signed_call(
"import_finalized_epoch_header",
(parameter,),
Options {
gas: Some(U256::from(10000000)),
gas_price: Some(U256::from(1300000000)),
..Default::default()
},
&self
.private_key
.ok_or_else(|| BridgerError::Custom("Private key is not valid".into()))?,
)
.await?;
Ok(tx)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_client() -> PangoroClient {
PangoroClient::new(
"https://pangoro-rpc.darwinia.network",
"0x6ac5ae3fa61b2cbea625dd24f57bdc3d952333c9",
None,
)
.unwrap()
}
#[ignore]
#[tokio::test]
async fn test_query_finalized_header() {
let client = test_client();
let checkpoint = client.get_finalized_checkpoint().await.unwrap();
println!("Finalized checkpoint: {:?}", checkpoint);
}
}