1use crate::{
4 api::Namespace,
5 helpers::{self, CallFuture},
6 types::{Address, Bytes, RawTransaction, TransactionRequest, H256, H520},
7 Transport,
8};
9
10#[derive(Debug, Clone)]
12pub struct Personal<T> {
13 transport: T,
14}
15
16impl<T: Transport> Namespace<T> for Personal<T> {
17 fn new(transport: T) -> Self
18 where
19 Self: Sized,
20 {
21 Personal { transport }
22 }
23
24 fn transport(&self) -> &T {
25 &self.transport
26 }
27}
28
29impl<T: Transport> Personal<T> {
30 pub fn list_accounts(&self) -> CallFuture<Vec<Address>, T::Out> {
32 CallFuture::new(self.transport.execute("personal_listAccounts", vec![]))
33 }
34
35 pub fn new_account(&self, password: &str) -> CallFuture<Address, T::Out> {
38 let password = helpers::serialize(&password);
39 CallFuture::new(self.transport.execute("personal_newAccount", vec![password]))
40 }
41
42 pub fn unlock_account(&self, address: Address, password: &str, duration: Option<u16>) -> CallFuture<bool, T::Out> {
45 let address = helpers::serialize(&address);
46 let password = helpers::serialize(&password);
47 let duration = helpers::serialize(&duration);
48 CallFuture::new(
49 self.transport
50 .execute("personal_unlockAccount", vec![address, password, duration]),
51 )
52 }
53
54 pub fn send_transaction(&self, transaction: TransactionRequest, password: &str) -> CallFuture<H256, T::Out> {
57 let transaction = helpers::serialize(&transaction);
58 let password = helpers::serialize(&password);
59 CallFuture::new(
60 self.transport
61 .execute("personal_sendTransaction", vec![transaction, password]),
62 )
63 }
64
65 pub fn sign(&self, data: Bytes, account: Address, password: &str) -> CallFuture<H520, T::Out> {
70 let data = helpers::serialize(&data);
71 let address = helpers::serialize(&account);
72 let password = helpers::serialize(&password);
73 CallFuture::new(self.transport.execute("personal_sign", vec![data, address, password]))
74 }
75
76 pub fn sign_transaction(
80 &self,
81 transaction: TransactionRequest,
82 password: &str,
83 ) -> CallFuture<RawTransaction, T::Out> {
84 let transaction = helpers::serialize(&transaction);
85 let password = helpers::serialize(&password);
86 CallFuture::new(
87 self.transport
88 .execute("personal_signTransaction", vec![transaction, password]),
89 )
90 }
91
92 pub fn import_raw_key(&self, private_key: &[u8; 32], password: &str) -> CallFuture<Address, T::Out> {
95 let private_key = hex::encode(private_key);
96 let private_key = helpers::serialize(&private_key);
97 let password = helpers::serialize(&password);
98
99 CallFuture::new(
100 self.transport
101 .execute("personal_importRawKey", vec![private_key, password]),
102 )
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::Personal;
109 use crate::{
110 api::Namespace,
111 rpc::Value,
112 types::{Address, Bytes, RawTransaction, TransactionRequest, H160, H520},
113 };
114 use hex_literal::hex;
115
116 const EXAMPLE_TX: &str = r#"{
117 "raw": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
118 "tx": {
119 "hash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
120 "nonce": "0x0",
121 "blockHash": "0xbeab0aa2411b7ab17f30a99d3cb9c6ef2fc5426d6ad6fd9e2a26a6aed1d1055b",
122 "blockNumber": "0x15df",
123 "transactionIndex": "0x1",
124 "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
125 "to": "0x853f43d8a49eeb85d32cf465507dd71d507100c1",
126 "value": "0x7f110",
127 "gas": "0x7f110",
128 "gasPrice": "0x09184e72a000",
129 "input": "0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360"
130 }
131 }"#;
132
133 rpc_test! (
134 Personal:list_accounts => "personal_listAccounts";
135 Value::Array(vec![Value::String("0x0000000000000000000000000000000000000123".into())]) => vec![Address::from_low_u64_be(0x123)]
136 );
137
138 rpc_test! (
139 Personal:new_account, "hunter2" => "personal_newAccount", vec![r#""hunter2""#];
140 Value::String("0x0000000000000000000000000000000000000123".into()) => Address::from_low_u64_be(0x123)
141 );
142
143 rpc_test! (
144 Personal:unlock_account, Address::from_low_u64_be(0x123), "hunter2", None
145 =>
146 "personal_unlockAccount", vec![r#""0x0000000000000000000000000000000000000123""#, r#""hunter2""#, r#"null"#];
147 Value::Bool(true) => true
148 );
149
150 rpc_test! (
151 Personal:send_transaction, TransactionRequest {
152 from: Address::from_low_u64_be(0x123), to: Some(Address::from_low_u64_be(0x123)),
153 gas: None, gas_price: Some(0x1.into()),
154 value: Some(0x1.into()), data: None,
155 nonce: None, condition: None,
156 transaction_type: None, access_list: None,
157 max_fee_per_gas: None, max_priority_fee_per_gas: None,
158 }, "hunter2"
159 =>
160 "personal_sendTransaction", vec![r#"{"from":"0x0000000000000000000000000000000000000123","gasPrice":"0x1","to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#, r#""hunter2""#];
161 Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()) => Address::from_low_u64_be(0x123)
162 );
163
164 rpc_test! (
165 Personal:sign_transaction, TransactionRequest {
166 from: hex!("407d73d8a49eeb85d32cf465507dd71d507100c1").into(),
167 to: Some(hex!("853f43d8a49eeb85d32cf465507dd71d507100c1").into()),
168 gas: Some(0x7f110.into()),
169 gas_price: Some(0x09184e72a000u64.into()),
170 value: Some(0x7f110.into()),
171 data: Some(hex!("603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360").into()),
172 nonce: Some(0x0.into()),
173 condition: None,
174 transaction_type: None,
175 access_list: None,
176 max_fee_per_gas: None,
177 max_priority_fee_per_gas: None,
178 }, "hunter2"
179 =>
180 "personal_signTransaction", vec![r#"{"data":"0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360","from":"0x407d73d8a49eeb85d32cf465507dd71d507100c1","gas":"0x7f110","gasPrice":"0x9184e72a000","nonce":"0x0","to":"0x853f43d8a49eeb85d32cf465507dd71d507100c1","value":"0x7f110"}"#, r#""hunter2""#];
181 ::serde_json::from_str(EXAMPLE_TX).unwrap()
182 => ::serde_json::from_str::<RawTransaction>(EXAMPLE_TX).unwrap()
183 );
184
185 rpc_test! {
186 Personal:import_raw_key, &[0u8; 32], "hunter2" =>
187 "personal_importRawKey", vec![r#""0000000000000000000000000000000000000000000000000000000000000000""#, r#""hunter2""#];
188 Value::String("0x0000000000000000000000000000000000000123".into()) => Address::from_low_u64_be(0x123)
189 }
190
191 rpc_test! {
192 Personal:sign, Bytes(hex!("7f0d39b8347598e20466233ce2fb3e824f0f93dfbf233125d3ab09b172c62591ec24dc84049242e364895c3abdbbd843d4a0a188").to_vec()), H160(hex!("7f0d39b8347598e20466233ce2fb3e824f0f93df")), "hunter2"
193 =>
194 "personal_sign", vec![r#""0x7f0d39b8347598e20466233ce2fb3e824f0f93dfbf233125d3ab09b172c62591ec24dc84049242e364895c3abdbbd843d4a0a188""#, r#""0x7f0d39b8347598e20466233ce2fb3e824f0f93df""#, r#""hunter2""#];
195 Value::String("0xdac1cba443d72e2088ed0cd2e6608ce696eb4728caf119dcfeea752f57a1163274de0b25007aa70201d0d80190071b26be2287b4a473767e5f7bc443c080b4fc1c".into()) => H520(hex!("dac1cba443d72e2088ed0cd2e6608ce696eb4728caf119dcfeea752f57a1163274de0b25007aa70201d0d80190071b26be2287b4a473767e5f7bc443c080b4fc1c"))
196 }
197}