1use crate::client::RpcProvider;
2use crate::error::Error;
3use crate::wallet::Wallet;
4use crate::Result;
5use rootchain_core::types::{Address, TransactionType};
6use serde::Serialize;
7
8pub struct Contract<'a> {
9 provider: &'a RpcProvider,
10 address: Address,
11}
12
13impl<'a> Contract<'a> {
14 pub fn new(provider: &'a RpcProvider, address: Address) -> Self {
15 Self { provider, address }
16 }
17
18 pub async fn call<Args, Ret>(&self, method: &str, args: Args) -> Result<Ret>
20 where
21 Args: Serialize,
22 Ret: for<'de> serde::Deserialize<'de>,
23 {
24 let payload = bincode::serialize(&args).map_err(|e| Error::Internal(e.to_string()))?;
25
26 let resp: serde_json::Value = self
27 .provider
28 .call(
29 "rootchain_call",
30 serde_json::json!([self.address, method, hex::encode(payload)]),
31 )
32 .await?;
33
34 let output_hex = resp
35 .get("output")
36 .and_then(|v| v.as_str())
37 .ok_or_else(|| Error::Rpc("Missing output field".to_string()))?;
38
39 let output_bytes = hex::decode(output_hex).map_err(|e| Error::Internal(e.to_string()))?;
40
41 let ret: Ret =
42 bincode::deserialize(&output_bytes).map_err(|e| Error::Internal(e.to_string()))?;
43
44 Ok(ret)
45 }
46
47 pub async fn send<Args>(
49 &self,
50 wallet: &Wallet,
51 method: &str,
52 args: Args,
53 fee: u64,
54 nonce: u64,
55 ) -> Result<String>
56 where
57 Args: Serialize,
58 {
59 let mut payload = Vec::new();
60 payload.extend_from_slice(method.as_bytes());
62 payload.push(0); let arg_bytes = bincode::serialize(&args).map_err(|e| Error::Internal(e.to_string()))?;
65 payload.extend_from_slice(&arg_bytes);
66
67 let tx = crate::wallet::TransactionBuilder::new()
68 .tx_type(TransactionType::ContractCall)
69 .from(wallet.address())
70 .to(self.address)
71 .amount(0)
72 .fee(fee.into())
73 .nonce(nonce)
74 .payload(payload)
75 .build(wallet)?;
76
77 let tx_hex = hex::encode(bincode::serialize(&tx).unwrap());
78 self.provider.send_raw_transaction(&tx_hex).await
79 }
80}