Browse Source

Refactor `NearClient` and add documentation

	* Improve `NearClient` errors. For now, each action has its own distinguished error
	* Remove `commit_empty` and add `Output for function call.
	* Split RPC calls with an deserialization stage`
develop
Silvestr Predko 3 years ago
parent
commit
92620d016f

+ 2
- 5
near-client/Cargo.toml View File

@@ -4,16 +4,14 @@ version = "0.1.0"
4 4
 edition = "2021"
5 5
 authors = ["silvestr@relayz.io", "kyrylo@relayz.io"]
6 6
 description = """
7
+The basic implementation of NEAR RPC.
7 8
 """
8 9
 
9
-[lib]
10
-crate-type = ["cdylib", "rlib"]
11
-
12 10
 [dependencies]
13 11
 base64 = { version = "0.13" }
14 12
 bs58 = "0.4"
15 13
 borsh = "0.9"
16
-ed25519-dalek = "1"
14
+common-api = { path = "../common-api" }
17 15
 itertools = "0.10"
18 16
 near-account-id = "0.15"
19 17
 near-primitives = { version = "0.15", package = "near-primitives-core" }
@@ -25,7 +23,6 @@ thiserror = "1"
25 23
 url = "2"
26 24
 
27 25
 [dev-dependencies]
28
-anyhow = "1"
29 26
 git2 = "0.15.0"
30 27
 reqwest = { version = "0.11", features = ["json"] }
31 28
 rand = "0.8.5"

+ 247
- 238
near-client/src/client.rs View File

@@ -5,168 +5,248 @@ use near_primitives::{
5 5
 };
6 6
 
7 7
 use crate::{
8
-    rpc::client::RpcClient,
9
-    types::{
10
-        crypto::{ED25519PublicKey, ED25519SecretKey, ED25519Signature, Key, Keypair},
11
-        near::{
12
-            Action, AddKeyAction, Chunks, CreateAccountAction, DeleteAccountAction,
13
-            DeployContractAction, FinalExecutionOutcomeView, FinalExecutionStatus,
14
-            FunctionCallAction, SignedTransaction, Transaction, TransferAction, ViewAccessKey,
15
-            ViewResult,
16
-        },
8
+    near::{
9
+        Action, AddKeyAction, Chunks, CreateAccountAction, DeleteAccountAction,
10
+        DeployContractAction, FinalExecutionOutcomeView, FinalExecutionStatus, FunctionCallAction,
11
+        TransferAction, ViewAccessKey, ViewResult,
17 12
     },
18
-    Error,
13
+    rpc::client::RpcClient,
14
+    utils::{serialize_arguments, serialize_transaction, TransactionInfo},
15
+    Error, Result,
19 16
 };
20 17
 
21
-use serde::de::DeserializeOwned;
18
+use common_api::crypto::prelude::*;
19
+use serde::{de::DeserializeOwned, Deserialize, Serialize};
22 20
 use serde_json::{json, Value};
23 21
 use url::Url;
24 22
 
25
-type Result<T> = std::result::Result<T, Error>;
23
+use std::sync::{Arc, Mutex};
24
+
25
+type AtomicNonce = Arc<Mutex<Nonce>>;
26
+
27
+/// The finality param has two options: optimistic and final.
28
+#[derive(Serialize, Deserialize)]
29
+pub enum Finality {
30
+    /// Optimistic uses the latest block recorded on the node
31
+    /// that responded to your query (<1 second delay after the transaction is submitted)
32
+    #[serde(rename = "optimistic")]
33
+    Optimistic,
34
+    /// Final is for a block that has been validated on at least 66% of the nodes
35
+    /// in the network (usually takes 2 blocks / approx. 2 second delay)
36
+    #[serde(rename = "final")]
37
+    Final,
38
+}
26 39
 
40
+/// Used for signing transactions
27 41
 pub struct Signer {
28 42
     keypair: Keypair,
29
-    signer_acc: AccountId,
30
-    pub key_nonce: Nonce,
43
+    account_id: AccountId,
44
+    nonce: AtomicNonce,
31 45
 }
32 46
 
33 47
 impl Signer {
34
-    pub fn new(secret_key: &str, signer_acc: AccountId, key_nonce: Nonce) -> Result<Self> {
48
+    pub fn from_secret_str(secret_key: &str, account_id: AccountId, nonce: Nonce) -> Result<Self> {
35 49
         Ok(Self {
36
-            keypair: Keypair::from_encoded(secret_key)?,
37
-            signer_acc,
38
-            key_nonce,
50
+            keypair: Keypair::from_expanded_secret(secret_key).map_err(Error::CreateSigner)?,
51
+            account_id,
52
+            nonce: AtomicNonce::new(Mutex::new(nonce)),
39 53
         })
40 54
     }
41 55
 
42
-    // Temporary implementation
43
-    // TODO: refactor [`Signer`]
44
-    pub fn new_v1(
45
-        secret_key: &ED25519SecretKey,
46
-        signer_acc: AccountId,
47
-        key_nonce: Nonce,
48
-    ) -> Result<Self> {
49
-        let sk = ED25519SecretKey::from_bytes(&secret_key.to_bytes())?;
50
-        Ok(Self {
51
-            keypair: Keypair::new(sk),
52
-            signer_acc,
53
-            key_nonce,
54
-        })
56
+    pub fn from_secret(secret_key: Ed25519SecretKey, account_id: AccountId, nonce: Nonce) -> Self {
57
+        Self {
58
+            keypair: Keypair::new(secret_key),
59
+            account_id,
60
+            nonce: AtomicNonce::new(Mutex::new(nonce)),
61
+        }
55 62
     }
56 63
 
57
-    pub fn sign(&self, data: &[u8]) -> ED25519Signature {
64
+    /// Sign a transaction
65
+    ///
66
+    /// Arguments
67
+    ///
68
+    /// - data - Serialized transaction with a [Borsh](https://borsh.io/)
69
+    pub fn sign(&self, data: &[u8]) -> Ed25519Signature {
58 70
         self.keypair.sign(data)
59 71
     }
60 72
 
61
-    pub fn public_key(&self) -> ED25519PublicKey {
62
-        self.keypair.public_key
73
+    pub fn public_key(&self) -> &Ed25519PublicKey {
74
+        self.keypair.public_key()
63 75
     }
64 76
 
65
-    pub fn secret_key(&self) -> &ED25519SecretKey {
66
-        &self.keypair.secret_key
77
+    pub fn secret_key(&self) -> &Ed25519SecretKey {
78
+        self.keypair.secret_key()
67 79
     }
68 80
 
69 81
     pub fn account(&self) -> &AccountId {
70
-        &self.signer_acc
82
+        &self.account_id
71 83
     }
72 84
 
73 85
     pub fn nonce(&self) -> Nonce {
74
-        self.key_nonce
86
+        *self.nonce.lock().unwrap()
87
+    }
88
+
89
+    pub fn update_nonce(&self, nonce: Nonce) {
90
+        *self.nonce.lock().unwrap() = nonce;
91
+    }
92
+
93
+    pub fn increment_nonce(&self, value: u64) {
94
+        *self.nonce.lock().unwrap() += value;
75 95
     }
76 96
 }
77 97
 
78 98
 pub struct NearClient {
79
-    rpc_client: RpcClient,
99
+    pub(crate) rpc_client: RpcClient,
80 100
 }
81 101
 
82 102
 impl NearClient {
83 103
     pub fn new(url: Url) -> Result<Self> {
84 104
         Ok(Self {
85
-            rpc_client: RpcClient::new(url).map_err(|error| Error::Rpc {
86
-                error,
87
-                method: "create_new_near_client",
88
-            })?,
105
+            rpc_client: RpcClient::new(url).map_err(Error::CreateClient)?,
89 106
         })
90 107
     }
91 108
 
92
-    pub async fn block(&self) -> Result<CryptoHash> {
93
-        let chunks = self
94
-            .rpc_client
95
-            .request::<Chunks>("block", Some(json!({"finality": "optimistic"})))
109
+    /// Queries network and returns block for given height or hash
110
+    pub async fn block(&self, finality: Finality) -> Result<CryptoHash> {
111
+        self.rpc_client
112
+            .request("block", Some(json!({ "finality": finality })))
96 113
             .await
97
-            .map_err(|error| Error::Rpc {
98
-                error,
99
-                method: "block",
100
-            })?;
101
-
102
-        Ok(chunks
103
-            .chunks
104
-            .into_iter()
105
-            .next()
106
-            .ok_or(Error::EmptyBlock)?
107
-            .prev_block_hash)
114
+            .map_err(Error::BlockCall)
115
+            .and_then(|block_res| {
116
+                serde_json::from_value::<Chunks>(block_res).map_err(Error::DeserializeBlockChunks)
117
+            })
118
+            .and_then(|chunks| {
119
+                Ok(chunks
120
+                    .chunks
121
+                    .into_iter()
122
+                    .next()
123
+                    .ok_or(Error::EmptyBlock)?
124
+                    .prev_block_hash)
125
+            })
108 126
     }
109 127
 
128
+    /// Allows you to call a contract method as a view function.
129
+    ///
130
+    /// Arguments
131
+    ///
132
+    /// - contract_id - The [`AccountId`] where smart contract is located
133
+    /// - finality - [`Finality`]
134
+    /// - method - Function that is declared in a smart contract
135
+    /// - args - Function arguments, could be empty
110 136
     pub async fn view<'a, T: DeserializeOwned>(
111 137
         &'a self,
112 138
         contract_id: &'a AccountId,
139
+        finality: Finality,
113 140
         method: &'static str,
114 141
         args: Option<Value>,
115 142
     ) -> Result<T> {
116
-        let view_result = self
117
-            .rpc_client
118
-            .request::<ViewResult>(
143
+        self.rpc_client
144
+            .request(
119 145
                 "query",
120 146
                 Some(json!({
121 147
                     "request_type": "call_function",
122
-                    "finality": "optimistic",
148
+                    "finality": finality,
123 149
                     "account_id": contract_id,
124 150
                     "method_name": method,
125
-                    "args_base64": args
126
-                        .map(|value| serde_json::to_vec(&value))
127
-                        .transpose()
128
-                        .map_err(Error::ArgsSerialize)?
129
-                        .map(base64::encode)
130
-                        .unwrap_or_default()
151
+                    "args_base64": base64::encode(serialize_arguments(args)?)
131 152
                 })),
132 153
             )
133 154
             .await
134
-            .map_err(|error| Error::Rpc {
135
-                error,
136
-                method: "query",
137
-            })?;
138
-
139
-        serde_json::from_slice(&view_result.result).map_err(Error::DeserializeTxResp)
155
+            .map_err(Error::ViewCall)
156
+            .and_then(|it| {
157
+                serde_json::from_value::<ViewResult>(it).map_err(Error::DeserializeViewCall)
158
+            })
159
+            .and_then(|view_res| {
160
+                serde_json::from_slice(&view_res.result).map_err(Error::DeserializeViewResponse)
161
+            })
140 162
     }
141 163
 
164
+    /// Returns information about a single access key for given account
165
+    ///
166
+    /// Arguments
167
+    ///
168
+    /// - account_id - The user [`AccountId`] in a Near network
169
+    /// - public_key - The user [`Ed25519PublicKey`] in a Near network
142 170
     pub async fn view_access_key<'a>(
143 171
         &'a self,
144 172
         account_id: &'a AccountId,
145
-        public_key: &'a ED25519PublicKey,
173
+        public_key: &'a Ed25519PublicKey,
174
+        finality: Finality,
146 175
     ) -> Result<ViewAccessKey> {
147
-        let result = self
148
-            .rpc_client
149
-            .request::<ViewAccessKey>(
176
+        self.rpc_client
177
+            .request(
150 178
                 "query",
151 179
                 Some(json!({
152 180
                     "request_type": "view_access_key",
153
-                    "finality": "optimistic",
181
+                    "finality": finality,
154 182
                     "account_id": account_id,
155 183
                     "public_key": public_key,
156 184
                 })),
157 185
             )
158 186
             .await
159
-            .map_err(|error| Error::Rpc {
160
-                error,
161
-                method: "query",
187
+            .map_err(Error::ViewAccessKeyCall)
188
+            .and_then(|it| {
189
+                serde_json::from_value::<ViewAccessKey>(it)
190
+                    .map_err(Error::DeserializeViewAccessCall)
191
+            })
192
+    }
193
+
194
+    /// Queries status of a transaction by hash,
195
+    /// returning the final transaction result and details of all receipts.
196
+    ///
197
+    /// Arguments
198
+    ///
199
+    /// - transaction_id - Transaction [`CryptoHash`]
200
+    /// - signer - [`Signer`] that contain information regarding user [`Keypair`]
201
+    ///
202
+    /// Return
203
+    ///
204
+    /// If a transaction still processing will be returned an error [`Error::ViewTransaction`],
205
+    /// in this case can try to execute [`view_transaction`] one more time, or a several times.
206
+    /// If an error differs from [`Error::ViewTransaction`] that something goes totally wrong and
207
+    /// you should stop to try executing [`view_transaction`] with the same arguments/signer
208
+    pub async fn view_transaction<'a>(
209
+        &'a self,
210
+        transaction_id: &'a CryptoHash,
211
+        signer: &'a Signer,
212
+    ) -> Result<Output> {
213
+        let params = Value::Array(vec![
214
+            serde_json::to_value(transaction_id)
215
+                .map_err(|err| Error::SerializeTxViewArg("transaction_id", err))?,
216
+            serde_json::to_value(signer.account())
217
+                .map_err(|err| Error::SerializeTxViewArg("signer_acc_id", err))?,
218
+        ]);
219
+
220
+        let execution_outcome = self
221
+            .rpc_client
222
+            .request("EXPERIMENTAL_tx_status", Some(params))
223
+            .await
224
+            .map_err(Error::ViewTransaction)
225
+            .and_then(|execution_outcome| {
226
+                serde_json::from_value::<FinalExecutionOutcomeView>(execution_outcome)
227
+                    .map_err(Error::DeserializeExecutionOutcome)
162 228
             })?;
163 229
 
164
-        Ok(result)
230
+        match execution_outcome.status {
231
+            FinalExecutionStatus::Failure(err) => Err(Error::TxExecution(err)),
232
+            FinalExecutionStatus::SuccessValue(data) => {
233
+                signer.update_nonce(execution_outcome.transaction.nonce);
234
+                Ok(Output(data))
235
+            }
236
+            _ => Err(Error::TxNotStarted),
237
+        }
165 238
     }
166 239
 
240
+    /// Execute a transaction with a function call to the smart contract
241
+    ///
242
+    /// Arguments
243
+    ///
244
+    /// - signer - Transaction [`Signer`]
245
+    /// - contract_id - The [`AccountId`] where smart contract is located
246
+    /// - method - Function that is declared in a smart contract (Arguments fir function call provided later in a [`FunctionCallBuilder`])
167 247
     pub fn function_call<'a>(
168 248
         &'a self,
169
-        signer: &'a mut Signer,
249
+        signer: &'a Signer,
170 250
         contract_id: &'a AccountId,
171 251
         method: &'static str,
172 252
     ) -> FunctionCallBuilder {
@@ -176,26 +256,24 @@ impl NearClient {
176 256
 
177 257
     pub fn deploy_contract<'a>(
178 258
         &'a self,
179
-        signer: &'a mut Signer,
259
+        signer: &'a Signer,
180 260
         contract_id: &'a AccountId,
181 261
         wasm: Vec<u8>,
182
-    ) -> Call {
183
-        let transaction_info = TransactionInfo::new(self, signer, contract_id);
184
-
185
-        Call {
186
-            transaction_info,
262
+    ) -> FunctionCall {
263
+        FunctionCall {
264
+            info: TransactionInfo::new(self, signer, contract_id),
187 265
             actions: vec![Action::from(DeployContractAction { code: wasm })],
188 266
         }
189 267
     }
190 268
 
191 269
     pub fn create_account<'a>(
192 270
         &'a self,
193
-        signer: &'a mut Signer,
271
+        signer: &'a Signer,
194 272
         new_account_id: &'a AccountId,
195
-        new_account_pk: ED25519PublicKey,
273
+        new_account_pk: Ed25519PublicKey,
196 274
         amount: Balance,
197
-    ) -> Call {
198
-        let transaction_info = TransactionInfo::new(self, signer, new_account_id);
275
+    ) -> FunctionCall {
276
+        let info = TransactionInfo::new(self, signer, new_account_id);
199 277
         let actions = vec![
200 278
             CreateAccountAction {}.into(),
201 279
             AddKeyAction {
@@ -209,153 +287,38 @@ impl NearClient {
209 287
             TransferAction { deposit: amount }.into(),
210 288
         ];
211 289
 
212
-        Call {
213
-            transaction_info,
214
-            actions,
215
-        }
290
+        FunctionCall { info, actions }
216 291
     }
217 292
 
218 293
     pub fn delete_account<'a>(
219 294
         &'a self,
220
-        signer: &'a mut Signer,
295
+        signer: &'a Signer,
221 296
         account_id: &'a AccountId,
222 297
         beneficiary_acc_id: &'a AccountId,
223
-    ) -> Call {
224
-        let transaction_info = TransactionInfo::new(self, signer, account_id);
298
+    ) -> FunctionCall {
299
+        let info = TransactionInfo::new(self, signer, account_id);
225 300
         let actions = vec![DeleteAccountAction {
226 301
             beneficiary_id: beneficiary_acc_id.clone(),
227 302
         }
228 303
         .into()];
229 304
 
230
-        Call {
231
-            transaction_info,
232
-            actions,
233
-        }
305
+        FunctionCall { info, actions }
234 306
     }
235 307
 }
236 308
 
237
-pub struct Call<'a> {
238
-    transaction_info: TransactionInfo<'a>,
239
-    actions: Vec<Action>,
240
-}
241
-
242
-impl<'a> Call<'a> {
243
-    pub async fn commit<T: DeserializeOwned>(self) -> Result<T> {
244
-        let transaction_bytes = serialize_transaction(&self.transaction_info, self.actions).await?;
245
-
246
-        let execution_outcome = self
247
-            .transaction_info
248
-            .client
249
-            .rpc_client
250
-            .request::<FinalExecutionOutcomeView>(
251
-                "broadcast_tx_commit",
252
-                Some(json!(vec![base64::encode(transaction_bytes)])),
253
-            )
254
-            .await
255
-            .map_err(|error| Error::Rpc {
256
-                error,
257
-                method: "broadcast_tx_commit",
258
-            })?;
309
+/// Function call output.
310
+pub struct Output(Vec<u8>);
259 311
 
260
-        match execution_outcome.status {
261
-            FinalExecutionStatus::Failure(err) => Err(Error::TransactionExec(err)),
262
-            FinalExecutionStatus::SuccessValue(mut data) => {
263
-                let nonce = execution_outcome.transaction.nonce;
264
-                self.transaction_info.signer.key_nonce = nonce;
265
-                if data.is_empty() {
266
-                    data = serde_json::to_vec(&()).unwrap();
267
-                }
268
-                serde_json::from_slice::<T>(&data).map_err(Error::DeserializeTxResp)
269
-            }
270
-            _ => Err(Error::TxNotStarted),
271
-        }
272
-    }
273
-
274
-    pub async fn commit_empty(self) -> Result<()> {
275
-        let transaction_bytes = serialize_transaction(&self.transaction_info, self.actions).await?;
276
-        let execution_outcome = self
277
-            .transaction_info
278
-            .client
279
-            .rpc_client
280
-            .request::<FinalExecutionOutcomeView>(
281
-                "broadcast_tx_commit",
282
-                Some(json!(vec![base64::encode(transaction_bytes)])),
283
-            )
284
-            .await
285
-            .map_err(|error| Error::Rpc {
286
-                error,
287
-                method: "broadcast_tx_commit",
288
-            })?;
289
-        match execution_outcome.status {
290
-            FinalExecutionStatus::Failure(err) => Err(Error::TransactionExec(err)),
291
-            FinalExecutionStatus::SuccessValue(_) => {
292
-                let nonce = execution_outcome.transaction.nonce;
293
-                self.transaction_info.signer.key_nonce = nonce;
294
-                Ok(())
295
-            }
296
-            _ => Err(Error::TxNotStarted),
297
-        }
298
-    }
299
-
300
-    pub async fn commit_async(self) -> Result<String> {
301
-        let transaction_bytes = serialize_transaction(&self.transaction_info, self.actions).await?;
302
-        self.transaction_info
303
-            .client
304
-            .rpc_client
305
-            .request::<String>(
306
-                "broadcast_tx_async",
307
-                Some(json!(vec![base64::encode(transaction_bytes)])),
308
-            )
309
-            .await
310
-            .map_err(|error| Error::Rpc {
311
-                error,
312
-                method: "broadcast_tx_async",
313
-            })
314
-    }
315
-}
316
-
317
-pub struct TransactionInfo<'a> {
318
-    client: &'a NearClient,
319
-    signer: &'a mut Signer,
320
-    contract_id: &'a AccountId,
321
-}
322
-impl<'a> TransactionInfo<'a> {
323
-    fn new(client: &'a NearClient, signer: &'a mut Signer, contract_id: &'a AccountId) -> Self {
324
-        Self {
325
-            client,
326
-            signer,
327
-            contract_id,
328
-        }
312
+impl Output {
313
+    /// If function don't return anything it will return [`Error::DeserializeTransactionOutput`]
314
+    /// Or if you miss matching a return type
315
+    pub fn output<T: DeserializeOwned>(&self) -> Result<T> {
316
+        serde_json::from_slice::<T>(&self.0).map_err(Error::DeserializeTransactionOutput)
329 317
     }
330 318
 }
331 319
 
332
-async fn serialize_transaction<'a>(
333
-    transaction_info: &'a TransactionInfo<'_>,
334
-    actions: Vec<Action>,
335
-) -> Result<Vec<u8>> {
336
-    let block_hash = transaction_info.client.block().await?;
337
-
338
-    let transaction = Transaction {
339
-        signer_id: transaction_info.signer.account().clone(),
340
-        public_key: transaction_info.signer.public_key(),
341
-        nonce: transaction_info.signer.nonce() + 1,
342
-        receiver_id: transaction_info.contract_id.clone(),
343
-        block_hash,
344
-        actions,
345
-    };
346
-
347
-    let signed_transaction = sign_transaction(transaction_info.signer, transaction);
348
-    borsh::to_vec(&signed_transaction).map_err(Error::TransactionSerialize)
349
-}
350
-
351
-fn sign_transaction(signer: &Signer, transaction: Transaction) -> SignedTransaction {
352
-    let (hash, ..) = transaction.get_hash_and_size();
353
-    let signature = signer.keypair.sign(hash.0.as_ref());
354
-    SignedTransaction::new(signature, transaction)
355
-}
356
-
357 320
 pub struct FunctionCallBuilder<'a> {
358
-    transaction_info: TransactionInfo<'a>,
321
+    info: TransactionInfo<'a>,
359 322
     deposit: Balance,
360 323
     gas: Gas,
361 324
     args: Option<Value>,
@@ -363,9 +326,9 @@ pub struct FunctionCallBuilder<'a> {
363 326
 }
364 327
 
365 328
 impl<'a> FunctionCallBuilder<'a> {
366
-    fn new(transaction_info: TransactionInfo<'a>, method_name: &'a str) -> Self {
329
+    fn new(info: TransactionInfo<'a>, method_name: &'a str) -> Self {
367 330
         Self {
368
-            transaction_info,
331
+            info,
369 332
             method_name,
370 333
             gas: Default::default(),
371 334
             args: Default::default(),
@@ -378,6 +341,7 @@ impl<'a> FunctionCallBuilder<'a> {
378 341
         self
379 342
     }
380 343
 
344
+    /// Amount of gas that will be hold for function execution
381 345
     pub fn gas(mut self, gas: Gas) -> Self {
382 346
         self.gas = gas;
383 347
         self
@@ -388,28 +352,73 @@ impl<'a> FunctionCallBuilder<'a> {
388 352
         self
389 353
     }
390 354
 
391
-    pub fn build(self) -> Result<Call<'a>> {
392
-        let args = self
393
-            .args
394
-            .as_ref()
395
-            .map(serde_json::to_vec)
396
-            .transpose()
397
-            .map_err(Error::ArgsSerialize)?
398
-            .unwrap_or_default();
399
-
355
+    pub fn build(self) -> Result<FunctionCall<'a>> {
400 356
         let action = Action::from(FunctionCallAction {
401 357
             method_name: self.method_name.to_string(),
402
-            args,
358
+            args: serialize_arguments(self.args)?,
403 359
             gas: self.gas,
404 360
             deposit: self.deposit,
405 361
         });
406 362
 
407
-        Ok(Call {
408
-            transaction_info: self.transaction_info,
363
+        Ok(FunctionCall {
364
+            info: self.info,
409 365
             actions: vec![action],
410 366
         })
411 367
     }
412 368
 }
413 369
 
414
-#[cfg(test)]
415
-mod tests {}
370
+pub struct FunctionCall<'a> {
371
+    info: TransactionInfo<'a>,
372
+    actions: Vec<Action>,
373
+}
374
+
375
+impl<'a> FunctionCall<'a> {
376
+    /// Sends a transaction and waits until transaction is fully complete. (Has a 10 second timeout)
377
+    pub async fn commit(self, block_finality: Finality) -> Result<Output> {
378
+        let transaction_bytes =
379
+            serialize_transaction(&self.info, self.actions, block_finality).await?;
380
+
381
+        let execution_outcome = self
382
+            .info
383
+            .rpc()
384
+            .request(
385
+                "broadcast_tx_commit",
386
+                Some(json!(vec![base64::encode(transaction_bytes)])),
387
+            )
388
+            .await
389
+            .map_err(Error::CommitTransaction)
390
+            .and_then(|execution_outcome| {
391
+                serde_json::from_value::<FinalExecutionOutcomeView>(execution_outcome)
392
+                    .map_err(Error::DeserializeExecutionOutcome)
393
+            })?;
394
+
395
+        match execution_outcome.status {
396
+            FinalExecutionStatus::Failure(err) => Err(Error::TxExecution(err)),
397
+            FinalExecutionStatus::SuccessValue(data) => {
398
+                self.info
399
+                    .signer()
400
+                    .update_nonce(execution_outcome.transaction.nonce);
401
+
402
+                Ok(Output(data))
403
+            }
404
+            _ => Err(Error::TxNotStarted),
405
+        }
406
+    }
407
+
408
+    /// Sends a transaction and immediately returns transaction hash.
409
+    pub async fn commit_async(self, block_finality: Finality) -> Result<CryptoHash> {
410
+        let transaction_bytes =
411
+            serialize_transaction(&self.info, self.actions, block_finality).await?;
412
+        self.info
413
+            .rpc()
414
+            .request(
415
+                "broadcast_tx_async",
416
+                Some(json!(vec![base64::encode(transaction_bytes)])),
417
+            )
418
+            .await
419
+            .map_err(Error::CommitAsyncTransaction)
420
+            .and_then(|id| {
421
+                serde_json::from_value::<CryptoHash>(id).map_err(Error::DeserializeTransactionId)
422
+            })
423
+    }
424
+}

+ 44
- 50
near-client/src/lib.rs View File

@@ -1,59 +1,53 @@
1
-use prelude::TxExecutionError;
1
+mod rpc;
2
+mod utils;
2 3
 
3 4
 pub mod client;
4
-pub mod rpc;
5
-pub mod types;
5
+pub mod near;
6 6
 
7
-pub mod prelude {
8
-    pub use super::types::{
9
-        self,
10
-        crypto::{ED25519PublicKey, ED25519Signature, Keypair},
11
-        near::TxExecutionError,
12
-    };
13
-}
7
+type Result<T> = std::result::Result<T, Error>;
14 8
 
15 9
 #[derive(Debug, thiserror::Error)]
16 10
 pub enum Error {
17
-    #[error("{0}")]
18
-    Type(types::Error),
19
-    #[error("Rpc request failed for [\"{method}\"] with {error}")]
20
-    Rpc {
21
-        error: rpc::Error,
22
-        method: &'static str,
23
-    },
11
+    #[error("Failed to create a signer, cause [\"{0}\"]")]
12
+    CreateSigner(common_api::crypto::Error),
13
+    #[error("Transaction not started")]
14
+    TxNotStarted,
15
+    #[error("Transaction failed during execution, cause [\"{0:?}\"]")]
16
+    TxExecution(near::TxExecutionError),
17
+    #[error("Transaction serialization error: [\"{0}\"]")]
18
+    TxSerialization(std::io::Error),
19
+    #[error("Couldn't serialize an argument [\"{0}\"] to view a transaction, cause: [\"{1}\"]")]
20
+    SerializeTxViewArg(&'static str, serde_json::Error),
21
+    #[error("Couldn't serialize arguments for view or function call, cause: [\"{0}\"]")]
22
+    ArgsSerialization(serde_json::Error),
23
+    #[error("Client creation failed, cause: [\"{0}\"]")]
24
+    CreateClient(rpc::Error),
25
+    #[error("Can't view a transaction, cause: [\"{0}\"]")]
26
+    ViewTransaction(rpc::Error),
27
+    #[error("Transaction commit failed with an error, cause: [\"{0}\"]")]
28
+    CommitTransaction(rpc::Error),
29
+    #[error("Transaction async commit failed with an error, cause: [\"{0}\"]")]
30
+    CommitAsyncTransaction(rpc::Error),
31
+    #[error("Block call failed with an error: \"{0}\"")]
32
+    BlockCall(rpc::Error),
24 33
     #[error("Couldn't get a previous block hash")]
25 34
     EmptyBlock,
26
-    #[error("Couldn't serialize function arguments {0}")]
27
-    ArgsSerialize(serde_json::Error),
28
-    #[error("Couldn't deserialize tx response {0}")]
29
-    DeserializeTxResp(serde_json::Error),
30
-    #[error("Borsh can't serialize transaction {0}")]
31
-    TransactionSerialize(std::io::Error),
32
-    #[error("Execution of transaction failed {0:?}")]
33
-    TransactionExec(TxExecutionError),
34
-    #[error("Transaction not started yet")]
35
-    TxNotStarted,
36
-    #[error("Rpc:")]
37
-    NoSigner,
38
-}
39
-
40
-impl From<types::Error> for Error {
41
-    fn from(err: types::Error) -> Self {
42
-        Self::Type(err)
43
-    }
44
-}
45
-
46
-pub fn add(left: usize, right: usize) -> usize {
47
-    left + right
48
-}
49
-
50
-#[cfg(test)]
51
-mod tests {
52
-    use super::*;
53
-
54
-    #[test]
55
-    fn it_works() {
56
-        let result = add(2, 2);
57
-        assert_eq!(result, 4);
58
-    }
35
+    #[error("Access key call failed with an error: \"{0}\"")]
36
+    ViewAccessKeyCall(rpc::Error),
37
+    #[error("View call failed with an error: \"{0}\"")]
38
+    ViewCall(rpc::Error),
39
+    #[error("Couldn't deserialize a transaction function output, cause: [\"{0}\"]")]
40
+    DeserializeTransactionOutput(serde_json::Error),
41
+    #[error("Couldn't deserialize a transaction outcome, cause: [\"{0}\"]")]
42
+    DeserializeExecutionOutcome(serde_json::Error),
43
+    #[error("Couldn't deserialize a transaction id, cause: [\"{0}\"]")]
44
+    DeserializeTransactionId(serde_json::Error),
45
+    #[error("Couldn't deserialize a view call result, cause [\"{0}\"]")]
46
+    DeserializeViewCall(serde_json::Error),
47
+    #[error("Couldn't deserialize a view response, cause [\"{0}\"]")]
48
+    DeserializeViewResponse(serde_json::Error),
49
+    #[error("Couldn't deserialize a block chunks, cause: [\"{0}\"]")]
50
+    DeserializeBlockChunks(serde_json::Error),
51
+    #[error("Can't deserialize an access key response, cause: [\"{0}\"]")]
52
+    DeserializeViewAccessCall(serde_json::Error),
59 53
 }

near-client/src/types/near.rs → near-client/src/near.rs View File

@@ -1,4 +1,9 @@
1
-use crate::types::crypto::{ED25519PublicKey, ED25519Signature};
1
+//! ### Near RPC types
2
+//! ---
3
+//! Mostly it's a copy-paste from a [`nearcore`](https://github.com/near/nearcore)
4
+//! with a some additional tunning for a Relayz requirements
5
+
6
+use common_api::crypto::prelude::*;
2 7
 
3 8
 use borsh::{BorshDeserialize, BorshSerialize};
4 9
 use near_account_id::AccountId;
@@ -27,7 +32,7 @@ pub struct Transaction {
27 32
     pub signer_id: AccountId,
28 33
     /// A public key of the access key which was used to sign an account.
29 34
     /// Access key holds permissions for calling certain kinds of actions.
30
-    pub public_key: ED25519PublicKey,
35
+    pub public_key: Ed25519PublicKey,
31 36
     /// Nonce is used to determine order of transaction in the pool.
32 37
     /// It increments for a combination of `signer_id` and `public_key`
33 38
     pub nonce: Nonce,
@@ -163,7 +168,7 @@ pub struct StakeAction {
163 168
     #[serde(with = "dec_format")]
164 169
     pub stake: Balance,
165 170
     /// Validator key which will be used to sign transactions on behalf of singer_id
166
-    pub public_key: ED25519PublicKey,
171
+    pub public_key: Ed25519PublicKey,
167 172
 }
168 173
 
169 174
 impl From<StakeAction> for Action {
@@ -175,7 +180,7 @@ impl From<StakeAction> for Action {
175 180
 #[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
176 181
 pub struct AddKeyAction {
177 182
     /// A public key which will be associated with an access_key
178
-    pub public_key: ED25519PublicKey,
183
+    pub public_key: Ed25519PublicKey,
179 184
     /// An access key with the permission
180 185
     pub access_key: AccessKey,
181 186
 }
@@ -189,7 +194,7 @@ impl From<AddKeyAction> for Action {
189 194
 #[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
190 195
 pub struct DeleteKeyAction {
191 196
     /// A public key associated with the access_key to be deleted.
192
-    pub public_key: ED25519PublicKey,
197
+    pub public_key: Ed25519PublicKey,
193 198
 }
194 199
 
195 200
 impl From<DeleteKeyAction> for Action {
@@ -213,7 +218,7 @@ impl From<DeleteAccountAction> for Action {
213 218
 #[borsh_init(init)]
214 219
 pub struct SignedTransaction {
215 220
     pub transaction: Transaction,
216
-    pub signature: ED25519Signature,
221
+    pub signature: Ed25519Signature,
217 222
     #[borsh_skip]
218 223
     hash: CryptoHash,
219 224
     #[borsh_skip]
@@ -221,7 +226,7 @@ pub struct SignedTransaction {
221 226
 }
222 227
 
223 228
 impl SignedTransaction {
224
-    pub fn new(signature: ED25519Signature, transaction: Transaction) -> Self {
229
+    pub fn new(signature: Ed25519Signature, transaction: Transaction) -> Self {
225 230
         let mut signed_tx = Self {
226 231
             signature,
227 232
             transaction,
@@ -268,11 +273,11 @@ impl Borrow<CryptoHash> for SignedTransaction {
268 273
 #[derive(Debug, Clone, Serialize, Deserialize)]
269 274
 pub struct SignedTransactionView {
270 275
     pub signer_id: AccountId,
271
-    pub public_key: ED25519PublicKey,
276
+    pub public_key: Ed25519PublicKey,
272 277
     pub nonce: Nonce,
273 278
     pub receiver_id: AccountId,
274 279
     pub actions: Vec<ActionView>,
275
-    pub signature: ED25519Signature,
280
+    pub signature: Ed25519Signature,
276 281
     pub hash: CryptoHash,
277 282
 }
278 283
 
@@ -387,14 +392,14 @@ pub enum ActionView {
387 392
     Stake {
388 393
         #[serde(with = "dec_format")]
389 394
         stake: Balance,
390
-        public_key: ED25519PublicKey,
395
+        public_key: Ed25519PublicKey,
391 396
     },
392 397
     AddKey {
393
-        public_key: ED25519PublicKey,
398
+        public_key: Ed25519PublicKey,
394 399
         access_key: AccessKeyView,
395 400
     },
396 401
     DeleteKey {
397
-        public_key: ED25519PublicKey,
402
+        public_key: Ed25519PublicKey,
398 403
     },
399 404
     DeleteAccount {
400 405
         beneficiary_id: AccountId,

+ 44
- 20
near-client/src/rpc/client.rs View File

@@ -1,6 +1,6 @@
1 1
 use reqwest::{
2 2
     header::{HeaderMap, CONTENT_TYPE},
3
-    Client, ClientBuilder,
3
+    Client, ClientBuilder, Response as Resp,
4 4
 };
5 5
 use serde::{Deserialize, Serialize};
6 6
 use serde_json::Value;
@@ -11,13 +11,19 @@ use url::Url;
11 11
 
12 12
 type Result<T> = std::result::Result<T, Error>;
13 13
 
14
-pub struct RpcClient {
14
+pub(crate) struct RpcClient {
15 15
     client: Client,
16 16
     url: Url,
17 17
 }
18 18
 
19 19
 impl RpcClient {
20
-    pub fn new(url: Url) -> Result<Self> {
20
+    /// Creates a [`reqwest`] client with headers:
21
+    /// [`CONTENT_TYPE`]: "application/json"
22
+    ///
23
+    /// Arguments
24
+    ///
25
+    /// - url - It's an RPC endpoint [`Url`]
26
+    pub(crate) fn new(url: Url) -> Result<Self> {
21 27
         let mut headers = HeaderMap::new();
22 28
         // It can't panic
23 29
         headers.insert(CONTENT_TYPE, "application/json".parse().unwrap());
@@ -29,11 +35,23 @@ impl RpcClient {
29 35
         Ok(Self { client, url })
30 36
     }
31 37
 
32
-    pub async fn request<T: serde::de::DeserializeOwned>(
33
-        &self,
34
-        method: &str,
35
-        params: Option<Value>,
36
-    ) -> Result<T> {
38
+    /// RPC call to the NEAR network
39
+    ///
40
+    /// Arguments
41
+    ///
42
+    /// - method - RPC method
43
+    /// - params - method arguments, could be empty
44
+    ///
45
+    /// Response example:
46
+    /// ```json
47
+    /// {
48
+    ///   "id": "dontcare",
49
+    ///   "jsonrpc": "2.0",
50
+    ///   "result": "...",
51
+    /// }
52
+    ///
53
+    /// ```
54
+    pub(crate) async fn request(&self, method: &str, params: Option<Value>) -> Result<Value> {
37 55
         let resp = self
38 56
             .client
39 57
             .post(self.url.clone())
@@ -43,11 +61,11 @@ impl RpcClient {
43 61
             )
44 62
             .send()
45 63
             .await
46
-            .and_then(reqwest::Response::error_for_status)
64
+            .and_then(Resp::error_for_status)
47 65
             .map_err(Error::RpcRequest)?;
48 66
 
49 67
         match resp
50
-            .json::<Response<T>>()
68
+            .json::<Response>()
51 69
             .await
52 70
             .map_err(Error::DeserializeRpcResponse)?
53 71
         {
@@ -88,21 +106,21 @@ impl<'a> Request<'a> {
88 106
 }
89 107
 
90 108
 #[derive(Debug, Serialize, Deserialize)]
91
-struct Response<T> {
109
+struct Response {
92 110
     /// JSON-RPC version.
93 111
     pub jsonrpc: String,
94 112
     /// Result.
95 113
     #[serde(flatten)]
96
-    pub result: RpcResult<T>,
114
+    pub result: RpcResult,
97 115
     /// Request ID
98 116
     pub id: String,
99 117
 }
100 118
 
101 119
 /// Near result format
102 120
 #[derive(Debug, Serialize, Deserialize)]
103
-enum RpcResult<T> {
121
+enum RpcResult {
104 122
     #[serde(rename = "result")]
105
-    Ok(T),
123
+    Ok(Value),
106 124
     #[serde(rename = "error")]
107 125
     Err(NearError),
108 126
 }
@@ -113,15 +131,21 @@ mod tests {
113 131
     use super::*;
114 132
 
115 133
     #[test]
116
-    fn test() {
134
+    fn response_sample() {
117 135
         let resp = Response {
118
-            jsonrpc: "some".to_owned(),
119
-            result: RpcResult::Ok("wef".to_owned()),
136
+            jsonrpc: "2.0".to_owned(),
137
+            result: RpcResult::Ok(Value::String("some value".to_owned())),
120 138
             id: "dontcare".to_owned(),
121 139
         };
122 140
 
123
-        let r = serde_json::to_string_pretty(&resp).unwrap();
124
-
125
-        println!("{}", r);
141
+        assert_eq!(
142
+            serde_json::to_value(&resp).unwrap(),
143
+            serde_json::to_value(&serde_json::json!({
144
+                "id": "dontcare",
145
+                "jsonrpc": "2.0",
146
+                "result": "some value",
147
+            }))
148
+            .unwrap()
149
+        );
126 150
     }
127 151
 }

+ 7
- 7
near-client/src/rpc/mod.rs View File

@@ -1,4 +1,4 @@
1
-pub mod client;
1
+pub(crate) mod client;
2 2
 
3 3
 use std::fmt::Display;
4 4
 
@@ -7,15 +7,15 @@ use serde_json::Value;
7 7
 
8 8
 #[derive(Debug, thiserror::Error)]
9 9
 pub enum Error {
10
-    #[error("Couldn't create a RpcClient: {0}")]
10
+    #[error("Couldn't create a RpcClient: [\"{0}\"]")]
11 11
     RpcClientCreate(reqwest::Error),
12
-    #[error("Rpc request failed with: {0}")]
12
+    #[error("Rpc request failed with: [\"{0}\"]")]
13 13
     RpcRequest(reqwest::Error),
14
-    #[error("Failed to serialize an RPC request: {0}")]
14
+    #[error("Failed to serialize an RPC request: [\"{0}\"]")]
15 15
     SerializeRpcRequest(serde_json::Error),
16
-    #[error("Failed to serialize an RPC request: {0}")]
16
+    #[error("Failed to deserialize an RPC response: [\"{0}\"]")]
17 17
     DeserializeRpcResponse(reqwest::Error),
18
-    #[error("Near protocol error: {0}")]
18
+    #[error("Near protocol error: [\"{0}\"]")]
19 19
     NearProtocol(NearError),
20 20
 }
21 21
 
@@ -38,7 +38,7 @@ impl Display for NearError {
38 38
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 39
         write!(
40 40
             f,
41
-            "Name: {} Msg: {} Cause: {} descr: {}",
41
+            "Name: {}, Message: {}, Cause: {}, Descr: {}",
42 42
             self.name, self.message, self.cause, self.data
43 43
         )
44 44
     }

+ 0
- 317
near-client/src/types/crypto.rs View File

@@ -1,317 +0,0 @@
1
-use borsh::{BorshDeserialize, BorshSerialize};
2
-use ed25519_dalek::{
3
-    ExpandedSecretKey, PublicKey, SecretKey, Signature, Verifier, PUBLIC_KEY_LENGTH,
4
-    SECRET_KEY_LENGTH, SIGNATURE_LENGTH,
5
-};
6
-use itertools::Itertools;
7
-use serde::{Deserialize, Serialize};
8
-use std::{
9
-    fmt::{Debug, Display},
10
-    hash::{Hash, Hasher},
11
-    io::{Error as IoError, ErrorKind},
12
-    str::FromStr,
13
-};
14
-
15
-use crate::types::Error;
16
-
17
-type Result<T> = std::result::Result<T, Error>;
18
-
19
-pub trait Key<T, const KEY_LENGTH: usize> {
20
-    fn from_string(key: &str) -> Result<T> {
21
-        let bs58_encoded = split_encoded_str(key)?;
22
-        let bytes = bs58::decode(bs58_encoded)
23
-            .into_vec()
24
-            .map_err(|err| Error::from_string::<T>(bs58_encoded.to_owned(), err.to_string()))?;
25
-        Self::from_bytes(&bytes)
26
-    }
27
-
28
-    fn to_string(&self) -> String {
29
-        format!("ed25519:{}", bs58::encode(self.to_bytes()).into_string())
30
-    }
31
-
32
-    fn from_bytes(bytes: &[u8]) -> Result<T>;
33
-    fn to_bytes(&self) -> [u8; KEY_LENGTH];
34
-}
35
-
36
-#[derive(Copy, Clone, Default, Eq, PartialEq)]
37
-pub struct ED25519PublicKey(PublicKey);
38
-
39
-impl ED25519PublicKey {
40
-    pub fn verify(&self, data: &[u8], signature: &ED25519Signature) -> Result<()> {
41
-        self.0
42
-            .verify(data, &signature.0)
43
-            .map_err(|_| Error::Verification(*signature))
44
-    }
45
-
46
-    #[inline]
47
-    pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] {
48
-        self.0.as_bytes()
49
-    }
50
-}
51
-
52
-impl Key<ED25519PublicKey, PUBLIC_KEY_LENGTH> for ED25519PublicKey {
53
-    fn from_bytes(bytes: &[u8]) -> Result<ED25519PublicKey> {
54
-        PublicKey::from_bytes(bytes)
55
-            .map(Self)
56
-            .map_err(|err| Error::from_bytes::<ED25519PublicKey>(bytes, err.to_string()))
57
-    }
58
-
59
-    #[inline]
60
-    fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
61
-        self.0.to_bytes()
62
-    }
63
-}
64
-
65
-impl BorshDeserialize for ED25519PublicKey {
66
-    fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
67
-        if buf.len() != PUBLIC_KEY_LENGTH {
68
-            return Err(IoError::new(ErrorKind::InvalidData, format!("Couldn't deserialize a ED25519PublicKey, input buffer {} is greater or less than required", buf.len())));
69
-        }
70
-
71
-        // The first byte is a key type, let's skip it because currently is used ed25519 only
72
-        let temp_buf = std::mem::take(buf);
73
-        Ok(Self(PublicKey::from_bytes(&temp_buf[1..]).map_err(
74
-            |err| {
75
-                IoError::new(
76
-                    ErrorKind::InvalidData,
77
-                    format!("Couldn't deserialize a ED25519PublicKey because of: {err}"),
78
-                )
79
-            },
80
-        )?))
81
-    }
82
-}
83
-
84
-impl BorshSerialize for ED25519PublicKey {
85
-    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
86
-        BorshSerialize::serialize(&0_u8, writer)?;
87
-        writer.write_all(self.0.as_bytes())
88
-    }
89
-}
90
-
91
-impl From<&ED25519SecretKey> for ED25519PublicKey {
92
-    fn from(sk: &ED25519SecretKey) -> Self {
93
-        Self(PublicKey::from(&sk.0))
94
-    }
95
-}
96
-
97
-// This `Hash` implementation is safe since it retains the property
98
-// `k1 == k2 ⇒ hash(k1) == hash(k2)`.
99
-#[allow(clippy::derive_hash_xor_eq)]
100
-impl Hash for ED25519PublicKey {
101
-    fn hash<H: Hasher>(&self, state: &mut H) {
102
-        state.write_u8(0u8);
103
-        state.write(self.0.as_bytes());
104
-    }
105
-}
106
-
107
-impl Debug for ED25519PublicKey {
108
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
109
-        write!(f, "{}", self)
110
-    }
111
-}
112
-
113
-impl Display for ED25519PublicKey {
114
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115
-        write!(f, "{}", Key::to_string(self))
116
-    }
117
-}
118
-
119
-pub struct ED25519SecretKey(SecretKey);
120
-
121
-impl ED25519SecretKey {
122
-    pub fn sign(&self, data: &[u8], public_key: &ED25519PublicKey) -> ED25519Signature {
123
-        let expanded_key = ExpandedSecretKey::from(&self.0);
124
-        ED25519Signature(expanded_key.sign(data, &public_key.0))
125
-    }
126
-
127
-    #[inline]
128
-    pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] {
129
-        self.0.as_bytes()
130
-    }
131
-
132
-    pub fn from_encoded_expanded(key: &str) -> Result<Self> {
133
-        let bs58_encoded = split_encoded_str(key)?;
134
-        let expanded_key_bytes = bs58::decode(bs58_encoded).into_vec().map_err(|err| {
135
-            Error::from_string::<ED25519SecretKey>(bs58_encoded.to_owned(), err.to_string())
136
-        })?;
137
-        Self::from_bytes(&expanded_key_bytes[..32])
138
-    }
139
-}
140
-
141
-impl Key<ED25519SecretKey, SECRET_KEY_LENGTH> for ED25519SecretKey {
142
-    fn from_bytes(bytes: &[u8]) -> Result<ED25519SecretKey> {
143
-        SecretKey::from_bytes(bytes)
144
-            .map(Self)
145
-            .map_err(|err| Error::from_bytes::<ED25519SecretKey>(bytes, err.to_string()))
146
-    }
147
-
148
-    #[inline]
149
-    fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
150
-        self.0.to_bytes()
151
-    }
152
-}
153
-
154
-#[derive(Copy, Clone, Eq, PartialEq)]
155
-pub struct ED25519Signature(Signature);
156
-
157
-impl Key<ED25519Signature, SIGNATURE_LENGTH> for ED25519Signature {
158
-    fn from_bytes(bytes: &[u8]) -> Result<ED25519Signature> {
159
-        Signature::from_bytes(bytes)
160
-            .map(Self)
161
-            .map_err(|err| Error::from_bytes::<ED25519Signature>(bytes, err.to_string()))
162
-    }
163
-
164
-    fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
165
-        self.0.to_bytes()
166
-    }
167
-}
168
-
169
-impl BorshSerialize for ED25519Signature {
170
-    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
171
-        BorshSerialize::serialize(&0_u8, writer)?;
172
-        writer.write_all(&self.to_bytes())
173
-    }
174
-}
175
-
176
-impl BorshDeserialize for ED25519Signature {
177
-    fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
178
-        if buf.len() != SIGNATURE_LENGTH + 1 {
179
-            return Err(IoError::new(ErrorKind::InvalidData, format!("Couldn't deserialize a ED25519Signature, input buffer {} is greater or less than required", buf.len())));
180
-        }
181
-
182
-        // The first byte is a key type, let's skip it because currently is used ed25519 only
183
-        let temp_buf = std::mem::take(buf);
184
-        Self::from_bytes(&temp_buf[1..]).map_err(|err| {
185
-            IoError::new(
186
-                ErrorKind::InvalidData,
187
-                format!("Couldn't deserialize a ED25519Signature because of: {err}"),
188
-            )
189
-        })
190
-    }
191
-}
192
-
193
-#[allow(clippy::derive_hash_xor_eq)]
194
-impl Hash for ED25519Signature {
195
-    fn hash<H: Hasher>(&self, state: &mut H) {
196
-        self.to_bytes().hash(state);
197
-    }
198
-}
199
-
200
-impl Debug for ED25519Signature {
201
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
202
-        write!(f, "{}", self)
203
-    }
204
-}
205
-
206
-impl Display for ED25519Signature {
207
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208
-        write!(f, "{}", Key::to_string(self))
209
-    }
210
-}
211
-
212
-#[derive(Serialize, Deserialize)]
213
-pub struct Keypair {
214
-    pub public_key: ED25519PublicKey,
215
-    pub secret_key: ED25519SecretKey,
216
-}
217
-
218
-impl Keypair {
219
-    pub fn new(secret_key: ED25519SecretKey) -> Self {
220
-        let public_key = ED25519PublicKey::from(&secret_key);
221
-        Self {
222
-            public_key,
223
-            secret_key,
224
-        }
225
-    }
226
-
227
-    pub fn from_encoded(encoded: &str) -> Result<Self> {
228
-        let secret_key = ED25519SecretKey::from_encoded_expanded(encoded)?;
229
-        let public_key = ED25519PublicKey::from(&secret_key);
230
-        Ok(Self {
231
-            public_key,
232
-            secret_key,
233
-        })
234
-    }
235
-
236
-    pub fn sign(&self, data: &[u8]) -> ED25519Signature {
237
-        self.secret_key.sign(data, &self.public_key)
238
-    }
239
-
240
-    pub fn verify(&self, data: &[u8], signature: &ED25519Signature) -> Result<()> {
241
-        self.public_key.verify(data, signature)
242
-    }
243
-}
244
-
245
-macro_rules! util_impl {
246
-    ($key_type: ty) => {
247
-        impl From<$key_type> for String {
248
-            fn from(key: $key_type) -> Self {
249
-                Key::to_string(&key)
250
-            }
251
-        }
252
-
253
-        impl FromStr for $key_type {
254
-            type Err = Error;
255
-
256
-            fn from_str(s: &str) -> Result<Self> {
257
-                Self::from_string(s)
258
-            }
259
-        }
260
-    };
261
-}
262
-
263
-macro_rules! serde_impl {
264
-    ($key_type: ty) => {
265
-        impl serde::Serialize for $key_type {
266
-            fn serialize<S>(
267
-                &self,
268
-                serializer: S,
269
-            ) -> std::result::Result<<S as serde::Serializer>::Ok, <S as serde::Serializer>::Error>
270
-            where
271
-                S: serde::Serializer,
272
-            {
273
-                serializer.serialize_str(&Key::to_string(self))
274
-            }
275
-        }
276
-
277
-        impl<'de> serde::Deserialize<'de> for $key_type {
278
-            fn deserialize<D>(
279
-                deserializer: D,
280
-            ) -> std::result::Result<Self, <D as serde::Deserializer<'de>>::Error>
281
-            where
282
-                D: serde::Deserializer<'de>,
283
-            {
284
-                let s = <String as serde::Deserialize>::deserialize(deserializer)?;
285
-                s.parse().map_err(|err| {
286
-                    serde::de::Error::custom(format!("Deserialization failed: `{}`", err))
287
-                })
288
-            }
289
-        }
290
-    };
291
-}
292
-
293
-fn split_encoded_str(encoded: &str) -> Result<&str> {
294
-    match encoded.split(':').next_tuple() {
295
-        Some((key_type, bs58_encoded)) => {
296
-            if key_type != "ed25519" {
297
-                return Err(Error::UnknownKeyType(key_type.to_owned()));
298
-            }
299
-            Ok(bs58_encoded)
300
-        }
301
-        _ => Err(Error::UnknownKeyType(encoded.to_owned())),
302
-    }
303
-}
304
-
305
-serde_impl!(ED25519PublicKey);
306
-util_impl!(ED25519PublicKey);
307
-serde_impl!(ED25519SecretKey);
308
-util_impl!(ED25519SecretKey);
309
-serde_impl!(ED25519Signature);
310
-util_impl!(ED25519Signature);
311
-
312
-#[cfg(test)]
313
-mod tests {
314
-
315
-    #[test]
316
-    fn test() {}
317
-}

+ 0
- 50
near-client/src/types/mod.rs View File

@@ -1,50 +0,0 @@
1
-pub mod crypto;
2
-pub mod near;
3
-
4
-#[derive(thiserror::Error, Debug)]
5
-pub enum Error {
6
-    #[error(
7
-        "Couldn't convert key from bytes `{key_string}` into `{key_name}`, because of: {cause}"
8
-    )]
9
-    ConvertFromBytes {
10
-        key_name: &'static str,
11
-        key_string: String,
12
-        cause: String,
13
-    },
14
-    #[error(
15
-        "Couldn't convert key from string `{key_string}` into `{key_name}`, because of: {cause}"
16
-    )]
17
-    ConvertFromString {
18
-        key_name: &'static str,
19
-        key_string: String,
20
-        cause: String,
21
-    },
22
-    #[error("The key format `{0}` seems different from ed25519 format")]
23
-    UnknownKeyType(String),
24
-    #[error("Signature `{0}` verification failed")]
25
-    Verification(crypto::ED25519Signature),
26
-}
27
-
28
-impl Error {
29
-    pub(crate) fn from_string<T>(key_string: String, cause: String) -> Self {
30
-        Self::ConvertFromString {
31
-            key_name: std::any::type_name::<T>()
32
-                .rsplit("::")
33
-                .next()
34
-                .unwrap_or_default(),
35
-            key_string,
36
-            cause,
37
-        }
38
-    }
39
-
40
-    pub(crate) fn from_bytes<T>(data: &[u8], cause: String) -> Self {
41
-        Self::ConvertFromBytes {
42
-            key_name: std::any::type_name::<T>()
43
-                .rsplit("::")
44
-                .next()
45
-                .unwrap_or_default(),
46
-            key_string: bs58::encode(data).into_string(),
47
-            cause,
48
-        }
49
-    }
50
-}

+ 74
- 0
near-client/src/utils.rs View File

@@ -0,0 +1,74 @@
1
+use crate::{
2
+    client::{Finality, NearClient, Signer},
3
+    near::{Action, SignedTransaction, Transaction},
4
+    rpc::client::RpcClient,
5
+    Error, Result,
6
+};
7
+
8
+use near_primitives::account::id::AccountId;
9
+use serde_json::Value;
10
+
11
+pub(crate) struct TransactionInfo<'a> {
12
+    client: &'a NearClient,
13
+    signer: &'a Signer,
14
+    contract_id: &'a AccountId,
15
+}
16
+
17
+impl<'a> TransactionInfo<'a> {
18
+    pub(crate) fn new(
19
+        client: &'a NearClient,
20
+        signer: &'a Signer,
21
+        contract_id: &'a AccountId,
22
+    ) -> Self {
23
+        Self {
24
+            client,
25
+            signer,
26
+            contract_id,
27
+        }
28
+    }
29
+
30
+    pub(crate) fn rpc(&self) -> &RpcClient {
31
+        &self.client.rpc_client
32
+    }
33
+
34
+    pub(crate) fn signer(&self) -> &Signer {
35
+        self.signer
36
+    }
37
+}
38
+
39
+/// Serialize and sign a transaction
40
+/// During call it requests the most recent block [`CryptoHash`]
41
+pub(crate) async fn serialize_transaction<'a>(
42
+    info: &'a TransactionInfo<'_>,
43
+    actions: Vec<Action>,
44
+    block_finality: Finality,
45
+) -> Result<Vec<u8>> {
46
+    let block_hash = info.client.block(block_finality).await?;
47
+
48
+    let transaction = Transaction {
49
+        signer_id: info.signer.account().clone(),
50
+        public_key: *info.signer.public_key(),
51
+        nonce: info.signer.nonce() + 1,
52
+        receiver_id: info.contract_id.clone(),
53
+        block_hash,
54
+        actions,
55
+    };
56
+
57
+    let signed_transaction = sign_transaction(info.signer, transaction);
58
+    borsh::to_vec(&signed_transaction).map_err(Error::TxSerialization)
59
+}
60
+
61
+pub(crate) fn serialize_arguments(args: Option<Value>) -> Result<Vec<u8>> {
62
+    Ok(args
63
+        .as_ref()
64
+        .map(serde_json::to_vec)
65
+        .transpose()
66
+        .map_err(Error::ArgsSerialization)?
67
+        .unwrap_or_default())
68
+}
69
+
70
+pub(crate) fn sign_transaction(signer: &Signer, transaction: Transaction) -> SignedTransaction {
71
+    let (hash, ..) = transaction.get_hash_and_size();
72
+    let signature = signer.sign(hash.0.as_ref());
73
+    SignedTransaction::new(signature, transaction)
74
+}

+ 234
- 186
near-client/tests/rpc.rs View File

@@ -1,11 +1,8 @@
1
+use common_api::crypto::prelude::*;
1 2
 use git2::{Cred, RemoteCallbacks};
2
-use itertools::Itertools;
3 3
 use near_client::{
4
-    client::{NearClient, Signer},
5
-    types::{
6
-        crypto::{ED25519PublicKey, ED25519SecretKey, Key},
7
-        near::{ViewAccessKey, ViewAccessKeyResult},
8
-    },
4
+    client::{Finality, NearClient, Signer},
5
+    near::{ViewAccessKey, ViewAccessKeyResult},
9 6
 };
10 7
 use rand::{RngCore, SeedableRng};
11 8
 use rand_chacha::ChaChaRng;
@@ -19,57 +16,58 @@ use std::{
19 16
 use workspaces::{network::Sandbox, types::SecretKey, AccountId, Worker};
20 17
 
21 18
 // auxiliary structs and methods
22
-fn near_client(worker: &Worker<Sandbox>) -> anyhow::Result<NearClient> {
23
-    let rpc_url = Url::parse(format!("http://localhost:{}", worker.rpc_port()).as_str())?;
24
-    let client = NearClient::new(rpc_url)?;
25
-    Ok(client)
19
+fn near_client(worker: &Worker<Sandbox>) -> NearClient {
20
+    let rpc_url = Url::parse(format!("http://localhost:{}", worker.rpc_port()).as_str()).unwrap();
21
+    NearClient::new(rpc_url).unwrap()
26 22
 }
27 23
 
28 24
 async fn create_signer(
29 25
     worker: &Worker<Sandbox>,
30 26
     client: &NearClient,
31 27
     signer_acc_id: &AccountId,
32
-) -> anyhow::Result<Signer> {
33
-    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
34
-    let ws_secret_key_str = to_workspaces_sk(&secret_key);
35
-    let pk = ED25519PublicKey::from(&secret_key);
36
-    let ws_sk = SecretKey::from_str(&ws_secret_key_str)?;
37
-    let _ = worker.create_tla(signer_acc_id.clone(), ws_sk).await?;
28
+) -> Signer {
29
+    let sk = Ed25519SecretKey::try_from_bytes(&random_bits()).unwrap();
30
+    let pk = Ed25519PublicKey::from(&sk);
31
+    let keypair = Keypair::new(sk).to_string();
32
+    let workspaces_sk = SecretKey::from_str(&keypair).unwrap();
33
+    let _ = worker
34
+        .create_tla(signer_acc_id.clone(), workspaces_sk)
35
+        .await
36
+        .unwrap();
38 37
 
39
-    client
40
-        .view_access_key(signer_acc_id, &pk)
38
+    let view_access_key = client
39
+        .view_access_key(signer_acc_id, &pk, Finality::Optimistic)
41 40
         .await
42
-        .map(|access_key_view| match access_key_view.result {
43
-            ViewAccessKeyResult::Ok { nonce, .. } => {
44
-                let signer_acc = Signer::new(&ws_secret_key_str, signer_acc_id.clone(), nonce)?;
45
-                Ok(signer_acc)
46
-            }
47
-            ViewAccessKeyResult::Err { error, .. } => Err(anyhow::anyhow!(error)),
48
-        })?
41
+        .unwrap();
42
+
43
+    match view_access_key.result {
44
+        ViewAccessKeyResult::Ok { nonce, .. } => {
45
+            Signer::from_secret_str(&keypair, signer_acc_id.clone(), nonce).unwrap()
46
+        }
47
+        ViewAccessKeyResult::Err { error, .. } => panic!("{error}"),
48
+    }
49 49
 }
50 50
 
51
-async fn download_contract() -> anyhow::Result<Vec<u8>> {
51
+async fn download_contract() -> Vec<u8> {
52 52
     let target = "https://github.com/near-examples/FT/raw/master/res/fungible_token.wasm";
53 53
     let target_path = "../target/tmp-contracts";
54 54
     let fname = "contract.wasm";
55 55
     let full_dest = format!("{}/{}", target_path, fname);
56 56
 
57
-    let contract_bytes = if !Path::new(&full_dest).exists() {
57
+    if !Path::new(&full_dest).exists() {
58 58
         if !Path::new(&target_path).exists() {
59
-            create_dir(target_path)?;
59
+            create_dir(target_path).unwrap();
60 60
         };
61 61
 
62
-        let contract_bytes = reqwest::get(target).await?.bytes().await?;
63
-        write(full_dest, &contract_bytes)?;
62
+        let contract_bytes = reqwest::get(target).await.unwrap().bytes().await.unwrap();
63
+        write(full_dest, &contract_bytes).unwrap();
64 64
         contract_bytes.to_vec()
65 65
     } else {
66
-        read(&full_dest)?
67
-    };
68
-
69
-    Ok(contract_bytes)
66
+        read(&full_dest).unwrap()
67
+    }
70 68
 }
71 69
 
72
-async fn clone_and_compile_wasm() -> anyhow::Result<Vec<u8>> {
70
+async fn clone_and_compile_wasm() -> Vec<u8> {
73 71
     let tmp_path = "../target/tmp-contracts";
74 72
     let repo_path = format!("{}/near-smartcontracts", tmp_path);
75 73
     let target_path = format!("{}/test-contract", repo_path);
@@ -77,14 +75,15 @@ async fn clone_and_compile_wasm() -> anyhow::Result<Vec<u8>> {
77 75
 
78 76
     if !Path::new(&target_path).exists() {
79 77
         if !Path::new(&tmp_path).exists() {
80
-            create_dir(tmp_path)?;
78
+            create_dir(tmp_path).unwrap();
81 79
         }
82 80
 
83 81
         // Prepare callbacks.
84 82
         let mut callbacks = RemoteCallbacks::new();
85 83
         callbacks.credentials(|_, username_from_url, _| {
86 84
             let username = username_from_url
87
-                .ok_or_else(|| git2::Error::from_str("Parsing the given URL is failed"))?;
85
+                .ok_or_else(|| git2::Error::from_str("Parsing the given URL is failed"))
86
+                .unwrap();
88 87
             Cred::ssh_key_from_agent(username)
89 88
         });
90 89
 
@@ -98,195 +97,235 @@ async fn clone_and_compile_wasm() -> anyhow::Result<Vec<u8>> {
98 97
         builder.branch("main");
99 98
 
100 99
         // Clone the project.
101
-        builder.clone(repo_url, Path::new(&repo_path))?;
100
+        builder.clone(repo_url, Path::new(&repo_path)).unwrap();
102 101
     }
103
-    let wasm = workspaces::compile_project(&target_path).await?;
104 102
 
105
-    Ok(wasm)
103
+    workspaces::compile_project(&target_path).await.unwrap()
106 104
 }
107 105
 
108
-fn random_bits() -> [u8; 32] {
106
+fn random_bits() -> [u8; ED25519_SECRET_KEY_LENGTH] {
109 107
     let mut chacha = ChaChaRng::from_entropy();
110
-    let mut secret_bytes = [0_u8; 32];
108
+    let mut secret_bytes = [0_u8; ED25519_SECRET_KEY_LENGTH];
111 109
     chacha.fill_bytes(&mut secret_bytes);
112 110
     secret_bytes
113 111
 }
114 112
 
115
-fn to_workspaces_sk(sk: &ED25519SecretKey) -> String {
116
-    let pk = ED25519PublicKey::from(sk);
117
-    let keypair = sk
118
-        .as_bytes()
119
-        .iter()
120
-        .chain(pk.as_bytes().iter())
121
-        .copied()
122
-        .collect_vec();
123
-    format!("ed25519:{}", bs58::encode(keypair).into_string())
124
-}
125
-
126 113
 // tests themselves
127 114
 #[tokio::test]
128
-async fn contract_creation() -> anyhow::Result<()> {
129
-    let worker = workspaces::sandbox().await?;
130
-    let client = near_client(&worker)?;
115
+async fn contract_creation() {
116
+    let worker = workspaces::sandbox().await.unwrap();
117
+    let client = near_client(&worker);
131 118
     let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
132
-    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
133
-    let wasm = download_contract().await?;
119
+    let signer = create_signer(&worker, &client, &signer_account_id).await;
120
+    let wasm = download_contract().await;
134 121
 
135 122
     client
136
-        .deploy_contract(&mut signer, &signer_account_id, wasm)
137
-        .commit_empty()
138
-        .await?;
139
-
140
-    Ok(())
123
+        .deploy_contract(&signer, &signer_account_id, wasm)
124
+        .commit(Finality::Optimistic)
125
+        .await
126
+        .unwrap();
141 127
 }
142 128
 
143 129
 #[tokio::test]
144
-async fn contract_function_call() -> anyhow::Result<()> {
145
-    let worker = workspaces::sandbox().await?;
146
-    let client = near_client(&worker)?;
130
+async fn contract_function_call() {
131
+    let worker = workspaces::sandbox().await.unwrap();
132
+    let client = near_client(&worker);
147 133
     let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
148
-    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
149
-    let wasm = download_contract().await?;
134
+    let signer = create_signer(&worker, &client, &signer_account_id).await;
135
+    let wasm = download_contract().await;
150 136
 
151 137
     client
152
-        .deploy_contract(&mut signer, &signer_account_id, wasm)
153
-        .commit_empty()
154
-        .await?;
138
+        .deploy_contract(&signer, &signer_account_id, wasm)
139
+        .commit(Finality::Optimistic)
140
+        .await
141
+        .unwrap();
155 142
 
156 143
     client
157
-        .function_call(&mut signer, &signer_account_id, "new_default_meta")
144
+        .function_call(&signer, &signer_account_id, "new_default_meta")
158 145
         .args(json!({
159 146
             "owner_id": &signer_account_id,
160 147
             "total_supply": "100",
161 148
         }))
162 149
         .gas(near_units::parse_gas!("300 T") as u64)
163
-        .build()?
164
-        .commit_empty()
165
-        .await?;
166
-
167
-    Ok(())
150
+        .build()
151
+        .unwrap()
152
+        .commit(Finality::Optimistic)
153
+        .await
154
+        .unwrap();
168 155
 }
169 156
 
170 157
 #[tokio::test]
171
-async fn multiple_tests() -> anyhow::Result<()> {
172
-    let worker = workspaces::sandbox().await?;
173
-    let client = near_client(&worker)?;
158
+async fn multiple_tests() {
159
+    let worker = workspaces::sandbox().await.unwrap();
160
+    let client = near_client(&worker);
174 161
     let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
175
-    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
176
-
177
-    let wasm = clone_and_compile_wasm().await?;
178
-
179
-    init_contract(&client, &signer_account_id, &mut signer, wasm).await?;
162
+    let signer = create_signer(&worker, &client, &signer_account_id).await;
180 163
 
181
-    fc_no_params(&client, &signer_account_id, &mut signer).await?;
182
-    fc_with_one_param_and_result(&client, &signer_account_id, &mut signer).await?;
183
-    fc_with_param_and_result(&client, &signer_account_id, &mut signer).await?;
164
+    let wasm = clone_and_compile_wasm().await;
184 165
 
185
-    view_no_params(&client, &signer_account_id).await?;
186
-    view_with_params(&client, &signer_account_id).await?;
187
-
188
-    Ok(())
166
+    init_contract(&client, &signer_account_id, &signer, wasm).await;
167
+    fc_no_params(&client, &signer_account_id, &signer).await;
168
+    fc_with_one_param_and_result(&client, &signer_account_id, &signer).await;
169
+    fc_with_param_and_result(&client, &signer_account_id, &signer).await;
170
+    view_no_params(&client, &signer_account_id).await;
171
+    view_with_params(&client, &signer_account_id).await;
189 172
 }
190 173
 
191 174
 async fn init_contract(
192 175
     client: &NearClient,
193 176
     contract_id: &AccountId,
194
-    signer: &mut Signer,
177
+    signer: &Signer,
195 178
     wasm: Vec<u8>,
196
-) -> anyhow::Result<()> {
179
+) {
197 180
     client
198 181
         .deploy_contract(signer, contract_id, wasm)
199
-        .commit_empty()
200
-        .await?;
201
-
202
-    Ok(())
182
+        .commit(Finality::Optimistic)
183
+        .await
184
+        .unwrap();
203 185
 }
204 186
 
205
-async fn view_no_params(client: &NearClient, contract_id: &AccountId) -> anyhow::Result<()> {
206
-    client.view::<u64>(contract_id, "show_id", None).await?;
207
-
208
-    Ok(())
187
+async fn view_no_params(client: &NearClient, contract_id: &AccountId) {
188
+    client
189
+        .view::<u64>(contract_id, Finality::Optimistic, "show_id", None)
190
+        .await
191
+        .unwrap();
209 192
 }
210 193
 
211
-async fn view_with_params(client: &NearClient, contract_id: &AccountId) -> anyhow::Result<()> {
194
+async fn view_with_params(client: &NearClient, contract_id: &AccountId) {
212 195
     client
213
-        .view::<String>(contract_id, "show_type", Some(json!({"is_message": true})))
214
-        .await?;
215
-
216
-    Ok(())
196
+        .view::<String>(
197
+            contract_id,
198
+            Finality::Optimistic,
199
+            "show_type",
200
+            Some(json!({"is_message": true})),
201
+        )
202
+        .await
203
+        .unwrap();
217 204
 }
218 205
 
219 206
 // fc = function call
220
-async fn fc_no_params(
221
-    client: &NearClient,
222
-    contract_id: &AccountId,
223
-    signer: &mut Signer,
224
-) -> anyhow::Result<()> {
207
+async fn fc_no_params(client: &NearClient, contract_id: &AccountId, signer: &Signer) {
225 208
     client
226 209
         .function_call(signer, contract_id, "increment")
227 210
         .gas(near_units::parse_gas!("300 T") as u64)
228
-        .build()?
229
-        .commit_empty()
230
-        .await?;
231
-
232
-    Ok(())
211
+        .build()
212
+        .unwrap()
213
+        .commit(Finality::Optimistic)
214
+        .await
215
+        .unwrap();
233 216
 }
234 217
 
235 218
 async fn fc_with_one_param_and_result(
236 219
     client: &NearClient,
237 220
     contract_id: &AccountId,
238
-    signer: &mut Signer,
239
-) -> anyhow::Result<()> {
221
+    signer: &Signer,
222
+) {
240 223
     let expected_result = "change message";
241 224
     let message = client
242 225
         .function_call(signer, contract_id, "change_message")
243 226
         .args(json!({ "message": expected_result }))
244 227
         .gas(near_units::parse_gas!("300 T") as u64)
245
-        .build()?
246
-        .commit::<String>()
247
-        .await?;
228
+        .build()
229
+        .unwrap()
230
+        .commit(Finality::Final)
231
+        .await
232
+        .unwrap()
233
+        .output::<String>()
234
+        .unwrap();
248 235
 
249 236
     assert_eq!(message, expected_result);
250
-
251
-    Ok(())
252 237
 }
253 238
 
254
-async fn fc_with_param_and_result(
255
-    client: &NearClient,
256
-    contract_id: &AccountId,
257
-    signer: &mut Signer,
258
-) -> anyhow::Result<()> {
239
+async fn fc_with_param_and_result(client: &NearClient, contract_id: &AccountId, signer: &Signer) {
259 240
     let expected_id = 666u64;
260 241
     let id = client
261 242
         .function_call(signer, contract_id, "change_id")
262 243
         .args(json!({ "id": expected_id }))
263 244
         .gas(near_units::parse_gas!("300 T") as u64)
264
-        .build()?
265
-        .commit::<u64>()
266
-        .await?;
245
+        .build()
246
+        .unwrap()
247
+        .commit(Finality::Final)
248
+        .await
249
+        .unwrap()
250
+        .output::<u64>()
251
+        .unwrap();
267 252
 
268 253
     assert_eq!(id, expected_id);
254
+}
255
+
256
+#[tokio::test]
257
+async fn async_transaction() {
258
+    let worker = workspaces::sandbox().await.unwrap();
259
+    let client = near_client(&worker);
260
+    let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
261
+    let signer = create_signer(&worker, &client, &signer_account_id).await;
262
+
263
+    let wasm = clone_and_compile_wasm().await;
264
+
265
+    client
266
+        .deploy_contract(&signer, &signer_account_id, wasm)
267
+        .commit(Finality::Optimistic)
268
+        .await
269
+        .unwrap();
270
+
271
+    let expected_result = "change message";
272
+    let transaction_id = client
273
+        .function_call(&signer, &signer_account_id, "change_message")
274
+        .args(json!({ "message": expected_result }))
275
+        .gas(near_units::parse_gas!("300 T") as u64)
276
+        .build()
277
+        .unwrap()
278
+        .commit_async(Finality::Final)
279
+        .await
280
+        .unwrap();
281
+
282
+    let (tx, rx) = tokio::sync::oneshot::channel::<()>();
283
+
284
+    tokio::spawn(async move {
285
+        tokio::time::timeout(std::time::Duration::from_secs(2), rx)
286
+            .await
287
+            .expect("Wait async transaction timeout")
288
+    });
289
+
290
+    loop {
291
+        let res = client.view_transaction(&transaction_id, &signer).await;
292
+
293
+        if let Err(near_client::Error::ViewTransaction(_)) = &res {
294
+            // try one more time
295
+            continue;
296
+        }
297
+
298
+        // cancel timeout
299
+        tx.send(()).unwrap();
300
+        let msg = res.unwrap().output::<String>().unwrap();
269 301
 
270
-    Ok(())
302
+        assert_eq!(msg, expected_result);
303
+        break;
304
+    }
271 305
 }
272 306
 
273 307
 #[tokio::test]
274
-async fn view_access_key_success() -> anyhow::Result<()> {
275
-    let worker = workspaces::sandbox().await?;
276
-    let client = near_client(&worker)?;
308
+async fn view_access_key_success() {
309
+    let worker = workspaces::sandbox().await.unwrap();
310
+    let client = near_client(&worker);
277 311
     let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
278
-    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
312
+    let signer = create_signer(&worker, &client, &signer_account_id).await;
279 313
 
280
-    let new_acc = AccountId::from_str("one.alice.test.near")?;
281
-    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
282
-    let pk = ED25519PublicKey::from(&secret_key);
314
+    let new_acc = AccountId::from_str("one.alice.test.near").unwrap();
315
+    let secret_key = Ed25519SecretKey::try_from_bytes(&random_bits()).unwrap();
316
+    let pk = Ed25519PublicKey::from(&secret_key);
283 317
 
284 318
     let _ = client
285
-        .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
286
-        .commit::<serde_json::Value>()
287
-        .await?;
319
+        .create_account(&signer, &new_acc, pk, near_units::parse_near!("3 N"))
320
+        .commit(Finality::Optimistic)
321
+        .await
322
+        .unwrap()
323
+        .output::<serde_json::Value>();
288 324
 
289
-    let access_key = client.view_access_key(&new_acc, &pk).await?;
325
+    let access_key = client
326
+        .view_access_key(&new_acc, &pk, Finality::Optimistic)
327
+        .await
328
+        .unwrap();
290 329
     assert!(matches!(
291 330
         access_key,
292 331
         ViewAccessKey {
@@ -294,20 +333,21 @@ async fn view_access_key_success() -> anyhow::Result<()> {
294 333
             ..
295 334
         }
296 335
     ));
297
-
298
-    Ok(())
299 336
 }
300 337
 
301 338
 #[tokio::test]
302
-async fn view_access_key_failure() -> anyhow::Result<()> {
303
-    let worker = workspaces::sandbox().await?;
304
-    let client = near_client(&worker)?;
339
+async fn view_access_key_failure() {
340
+    let worker = workspaces::sandbox().await.unwrap();
341
+    let client = near_client(&worker);
305 342
 
306
-    let new_acc = AccountId::from_str("one.alice.test.near")?;
307
-    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
308
-    let pk = ED25519PublicKey::from(&secret_key);
343
+    let new_acc = AccountId::from_str("one.alice.test.near").unwrap();
344
+    let secret_key = Ed25519SecretKey::try_from_bytes(&random_bits()).unwrap();
345
+    let pk = Ed25519PublicKey::from(&secret_key);
309 346
 
310
-    let access_key = client.view_access_key(&new_acc, &pk).await?;
347
+    let access_key = client
348
+        .view_access_key(&new_acc, &pk, Finality::Optimistic)
349
+        .await
350
+        .unwrap();
311 351
     assert!(matches!(
312 352
         access_key,
313 353
         ViewAccessKey {
@@ -315,27 +355,30 @@ async fn view_access_key_failure() -> anyhow::Result<()> {
315 355
             ..
316 356
         }
317 357
     ));
318
-
319
-    Ok(())
320 358
 }
321 359
 
322 360
 #[tokio::test]
323
-async fn create_account() -> anyhow::Result<()> {
324
-    let worker = workspaces::sandbox().await?;
325
-    let client = near_client(&worker)?;
361
+async fn create_account() {
362
+    let worker = workspaces::sandbox().await.unwrap();
363
+    let client = near_client(&worker);
326 364
     let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
327
-    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
365
+    let signer = create_signer(&worker, &client, &signer_account_id).await;
328 366
 
329
-    let new_acc = AccountId::from_str("one.alice.test.near")?;
330
-    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
331
-    let pk = ED25519PublicKey::from(&secret_key);
367
+    let new_acc = AccountId::from_str("one.alice.test.near").unwrap();
368
+    let secret_key = Ed25519SecretKey::try_from_bytes(&random_bits()).unwrap();
369
+    let pk = Ed25519PublicKey::from(&secret_key);
332 370
 
333 371
     let _ = client
334
-        .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
335
-        .commit::<serde_json::Value>()
336
-        .await?;
372
+        .create_account(&signer, &new_acc, pk, near_units::parse_near!("3 N"))
373
+        .commit(Finality::Final)
374
+        .await
375
+        .unwrap()
376
+        .output::<serde_json::Value>();
337 377
 
338
-    let access_key = client.view_access_key(&new_acc, &pk).await?;
378
+    let access_key = client
379
+        .view_access_key(&new_acc, &pk, Finality::Optimistic)
380
+        .await
381
+        .unwrap();
339 382
     assert!(matches!(
340 383
         access_key,
341 384
         ViewAccessKey {
@@ -343,27 +386,29 @@ async fn create_account() -> anyhow::Result<()> {
343 386
             ..
344 387
         }
345 388
     ));
346
-
347
-    Ok(())
348 389
 }
349 390
 
350 391
 #[tokio::test]
351
-async fn delete_account() -> anyhow::Result<()> {
352
-    let worker = workspaces::sandbox().await?;
353
-    let client = near_client(&worker)?;
392
+async fn delete_account() {
393
+    let worker = workspaces::sandbox().await.unwrap();
394
+    let client = near_client(&worker);
354 395
     let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
355
-    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
396
+    let signer = create_signer(&worker, &client, &signer_account_id).await;
356 397
 
357
-    let new_acc = AccountId::from_str("one.alice.test.near")?;
358
-    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
359
-    let pk = ED25519PublicKey::from(&secret_key);
398
+    let new_acc = AccountId::from_str("one.alice.test.near").unwrap();
399
+    let secret_key = Ed25519SecretKey::try_from_bytes(&random_bits()).unwrap();
400
+    let pk = Ed25519PublicKey::from(&secret_key);
360 401
 
361 402
     client
362
-        .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
363
-        .commit_empty()
364
-        .await?;
403
+        .create_account(&signer, &new_acc, pk, near_units::parse_near!("3 N"))
404
+        .commit(Finality::Final)
405
+        .await
406
+        .unwrap();
365 407
 
366
-    let access_key = client.view_access_key(&new_acc, &pk).await?;
408
+    let access_key = client
409
+        .view_access_key(&new_acc, &pk, Finality::Optimistic)
410
+        .await
411
+        .unwrap();
367 412
 
368 413
     let nonce = if let ViewAccessKey {
369 414
         result: ViewAccessKeyResult::Ok { nonce, .. },
@@ -375,13 +420,18 @@ async fn delete_account() -> anyhow::Result<()> {
375 420
         panic!("Can't view access key for just created account")
376 421
     };
377 422
 
378
-    let mut acc_signer = Signer::new(&secret_key.to_string(), new_acc.clone(), nonce)?;
423
+    let acc_signer = Signer::from_secret(secret_key, new_acc.clone(), nonce);
424
+
379 425
     client
380
-        .delete_account(&mut acc_signer, &new_acc, &signer_account_id)
381
-        .commit_empty()
382
-        .await?;
426
+        .delete_account(&acc_signer, &new_acc, &signer_account_id)
427
+        .commit(Finality::Final)
428
+        .await
429
+        .unwrap();
383 430
 
384
-    let access_key = client.view_access_key(&new_acc, &pk).await?;
431
+    let access_key = client
432
+        .view_access_key(&new_acc, &pk, Finality::Optimistic)
433
+        .await
434
+        .unwrap();
385 435
     assert!(matches!(
386 436
         access_key,
387 437
         ViewAccessKey {
@@ -389,6 +439,4 @@ async fn delete_account() -> anyhow::Result<()> {
389 439
             ..
390 440
         }
391 441
     ));
392
-
393
-    Ok(())
394 442
 }

+ 5
- 58
web-client/src/errors.rs View File

@@ -38,68 +38,15 @@ impl From<JsValue> for ApiError {
38 38
 #[wasm_bindgen]
39 39
 #[derive(Clone, Copy, Debug)]
40 40
 pub enum ErrorType {
41
-    Type,
42
-    Rpc,
43
-    EmptyBlock,
44
-    ArgsSerialize,
45
-    DeserializeTxResp,
46
-    TransactionSerialize,
47
-    TransactionExec,
48
-    TxNotStarted,
49
-    NoSigner,
50
-    ParseRpcUrl,
51
-    BadContractId,
41
+    NearClient,
52 42
     Other,
53 43
 }
54 44
 
55 45
 impl From<Error> for ApiError {
56 46
     fn from(error: Error) -> Self {
57
-        match error {
58
-            Error::Type(type_err) => Self {
59
-                r#type: ErrorType::Type,
60
-                msg: type_err.to_string(),
61
-            },
62
-            Error::Rpc { error, method } => Self {
63
-                r#type: ErrorType::Rpc,
64
-                msg: format!("Method: [\"{method}\"], Cause: \"{error}\""),
65
-            },
66
-            Error::EmptyBlock => Self {
67
-                r#type: ErrorType::EmptyBlock,
68
-                msg: error.to_string(),
69
-            },
70
-            Error::ArgsSerialize(err) => Self {
71
-                r#type: ErrorType::ArgsSerialize,
72
-                msg: err.to_string(),
73
-            },
74
-            Error::DeserializeTxResp(err) => Self {
75
-                r#type: ErrorType::DeserializeTxResp,
76
-                msg: err.to_string(),
77
-            },
78
-            Error::TransactionSerialize(err) => Self {
79
-                r#type: ErrorType::TransactionSerialize,
80
-                msg: err.to_string(),
81
-            },
82
-            Error::TransactionExec(err) => Self {
83
-                r#type: ErrorType::TransactionExec,
84
-                msg: format!("{err:?}"),
85
-            },
86
-            Error::TxNotStarted => Self {
87
-                r#type: ErrorType::TxNotStarted,
88
-                msg: error.to_string(),
89
-            },
90
-            Error::NoSigner => Self {
91
-                r#type: ErrorType::NoSigner,
92
-                msg: error.to_string(),
93
-            },
94
-        }
95
-    }
96
-}
97
-
98
-impl From<near_client::types::Error> for ApiError {
99
-    fn from(err: near_client::types::Error) -> Self {
100
-        Self {
101
-            r#type: ErrorType::Type,
102
-            msg: err.to_string(),
47
+        ApiError {
48
+            r#type: ErrorType::NearClient,
49
+            msg: error.to_string(),
103 50
         }
104 51
     }
105 52
 }
@@ -107,7 +54,7 @@ impl From<near_client::types::Error> for ApiError {
107 54
 impl From<ParseAccountError> for ApiError {
108 55
     fn from(err: ParseAccountError) -> Self {
109 56
         Self::new(
110
-            ErrorType::BadContractId,
57
+            ErrorType::NearClient,
111 58
             format!("AccountId has wrong format. Cause: {err}"),
112 59
         )
113 60
     }

+ 8
- 6
web-client/src/lib.rs View File

@@ -9,7 +9,7 @@ use rand::{RngCore, SeedableRng};
9 9
 use serde_json::json;
10 10
 use wasm_bindgen::prelude::*;
11 11
 
12
-use near_client::client::{NearClient, Signer};
12
+use near_client::client::{Finality, NearClient, Signer};
13 13
 
14 14
 use js_sys::Promise;
15 15
 use near_primitives::types::Nonce;
@@ -65,9 +65,9 @@ impl ProvisionerConfig {
65 65
         exchange_url: &str,
66 66
     ) -> Result<ProvisionerConfig> {
67 67
         let rpc_url = url::Url::from_str(rpc_url)
68
-            .map_err(|err| ApiError::new(ErrorType::ParseRpcUrl, err.to_string()))?;
68
+            .map_err(|err| ApiError::new(ErrorType::NearClient, err.to_string()))?;
69 69
         let key_exchange_url = url::Url::from_str(exchange_url)
70
-            .map_err(|err| ApiError::new(ErrorType::ParseRpcUrl, err.to_string()))?;
70
+            .map_err(|err| ApiError::new(ErrorType::NearClient, err.to_string()))?;
71 71
         let contract_id = AccountId::from_str(&contract_id).map_err(Into::<ApiError>::into)?;
72 72
 
73 73
         Ok(Self {
@@ -111,7 +111,7 @@ impl KeyProvisioner {
111 111
     ) -> Result<KeyProvisioner> {
112 112
         let client = Arc::new(NearClient::new(config.rpc_url).map_err(ApiError::from)?);
113 113
         let signer = Arc::new(Mutex::new(
114
-            Signer::new(
114
+            Signer::from_secret_str(
115 115
                 &keypair_str,
116 116
                 AccountId::from_str(&account_id).map_err(Into::<ApiError>::into)?,
117 117
                 nonce,
@@ -178,7 +178,7 @@ impl KeyProvisioner {
178 178
                 }))
179 179
                 .build()
180 180
                 .map_err(ApiError::from)?
181
-                .commit::<()>()
181
+                .commit(Finality::Final)
182 182
                 .await
183 183
                 .map_err(ApiError::from)?;
184 184
 
@@ -210,6 +210,7 @@ impl KeyProvisioner {
210 210
                             let resp = client_cp
211 211
                                 .view::<Option<String>>(
212 212
                                     &contract_cp,
213
+                                    Finality::Optimistic,
213 214
                                     "public_key",
214 215
                                     Some(json!({
215 216
                                         "id": meeting_id_cp,
@@ -324,6 +325,7 @@ impl KeyProvisioner {
324 325
                 let owner_pub_key = client
325 326
                     .view::<Option<String>>(
326 327
                         &contract_id,
328
+                        Finality::Optimistic,
327 329
                         "owner_key",
328 330
                         Some(serde_json::json!({
329 331
                             "id": meeting_id.to_string()
@@ -370,7 +372,7 @@ impl KeyProvisioner {
370 372
                 }))
371 373
                 .build()
372 374
                 .map_err(|err| ApiError::new(ErrorType::Other, err.to_string()))?
373
-                .commit::<()>()
375
+                .commit(Finality::Optimistic)
374 376
                 .await
375 377
                 .map_err(|err| ApiError::new(ErrorType::Other, err.to_string()))?;
376 378
 

+ 47
- 40
web-client/tests/integration.rs View File

@@ -1,7 +1,5 @@
1
-use near_client::{
2
-    client::{NearClient, Signer},
3
-    types::crypto::*,
4
-};
1
+use common_api::crypto::prelude::*;
2
+use near_client::client::{Finality, NearClient, Signer};
5 3
 use near_primitives::{account::id::AccountId, types::Balance};
6 4
 use rand::{RngCore, SeedableRng};
7 5
 use rand_chacha::ChaChaRng;
@@ -19,7 +17,7 @@ wasm_bindgen_test_configure!(run_in_browser);
19 17
 #[derive(Serialize, Deserialize)]
20 18
 struct ValidatorKey {
21 19
     account_id: AccountId,
22
-    public_key: ED25519PublicKey,
20
+    public_key: Ed25519PublicKey,
23 21
     secret_key: String,
24 22
 }
25 23
 
@@ -32,41 +30,46 @@ fn random_bits() -> [u8; 32] {
32 30
 
33 31
 async fn create_account(
34 32
     client: &NearClient,
35
-    validator: &mut Signer,
33
+    validator: &Signer,
36 34
     account_id_str: &str,
37 35
     amount: Balance,
38 36
 ) -> anyhow::Result<Signer> {
39 37
     let id = AccountId::from_str(account_id_str)?;
40
-    let sk = ED25519SecretKey::from_bytes(&random_bits())?;
41
-    let pk = ED25519PublicKey::from(&sk);
38
+    let sk = Ed25519SecretKey::try_from_bytes(&random_bits())?;
39
+    let pk = Ed25519PublicKey::from(&sk);
42 40
 
43 41
     client
44 42
         .create_account(validator, &id, pk, amount)
45
-        .commit_empty()
43
+        .commit(Finality::Final)
46 44
         .await?;
47 45
 
48
-    let nonce = Result::from(client.view_access_key(&id, &pk).await.unwrap())
49
-        .map_err(|err| anyhow::anyhow!(err))?;
46
+    let nonce = Result::from(
47
+        client
48
+            .view_access_key(&id, &pk, Finality::Optimistic)
49
+            .await
50
+            .unwrap(),
51
+    )
52
+    .map_err(|err| anyhow::anyhow!(err))?;
50 53
 
51
-    Ok(Signer::new_v1(&sk, id, nonce)?)
54
+    Ok(Signer::from_secret(sk, id, nonce))
52 55
 }
53 56
 
54 57
 async fn delete_account(
55 58
     client: &NearClient,
56
-    signer: &mut Signer,
59
+    signer: &Signer,
57 60
     beneficiary_acc_id: &AccountId,
58 61
 ) -> anyhow::Result<()> {
59 62
     let id = signer.account().clone();
60 63
     let pk = signer.public_key();
61 64
 
62
-    let nonce = Result::from(client.view_access_key(&id, &pk).await?)
65
+    let nonce = Result::from(client.view_access_key(&id, pk, Finality::Final).await?)
63 66
         .map_err(|err| anyhow::anyhow!(err))?;
64 67
 
65
-    signer.key_nonce = nonce;
68
+    signer.update_nonce(nonce);
66 69
 
67 70
     client
68 71
         .delete_account(signer, &id, beneficiary_acc_id)
69
-        .commit_empty()
72
+        .commit(Finality::Final)
70 73
         .await?;
71 74
     Ok(())
72 75
 }
@@ -86,12 +89,16 @@ async fn validator_account(
86 89
 ) -> anyhow::Result<Signer> {
87 90
     let key_nonce = Result::from(
88 91
         client
89
-            .view_access_key(&validator_key.account_id, &validator_key.public_key)
92
+            .view_access_key(
93
+                &validator_key.account_id,
94
+                &validator_key.public_key,
95
+                Finality::Final,
96
+            )
90 97
             .await?,
91 98
     )
92 99
     .map_err(|err| anyhow::anyhow!(err))?;
93 100
 
94
-    let signer = Signer::new(
101
+    let signer = Signer::from_secret_str(
95 102
         &validator_key.secret_key,
96 103
         validator_key.account_id.clone(),
97 104
         key_nonce,
@@ -121,40 +128,40 @@ async fn key_exchange() {
121 128
     let client = NearClient::new(rpc_url).unwrap();
122 129
 
123 130
     let validator_key = validator_key().await.unwrap();
124
-    let mut validator = validator_account(&client, validator_key).await.unwrap();
131
+    let validator = validator_account(&client, validator_key).await.unwrap();
125 132
 
126 133
     // create account for key-exchange
127 134
     // Alice is an initiator account
128
-    let mut alice_sg = create_account(
135
+    let alice_sg = create_account(
129 136
         &client,
130
-        &mut validator,
137
+        &validator,
131 138
         "alice.test.near",
132 139
         near_units::near::parse("10 N").unwrap(),
133 140
     )
134 141
     .await
135 142
     .unwrap();
136 143
 
137
-    let mut bob_sg = create_account(
144
+    let bob_sg = create_account(
138 145
         &client,
139
-        &mut validator,
146
+        &validator,
140 147
         "bob.test.near",
141 148
         near_units::near::parse("10 N").unwrap(),
142 149
     )
143 150
     .await
144 151
     .unwrap();
145 152
 
146
-    let mut karl_sg = create_account(
153
+    let karl_sg = create_account(
147 154
         &client,
148
-        &mut validator,
155
+        &validator,
149 156
         "karl.test.near",
150 157
         near_units::near::parse("10 N").unwrap(),
151 158
     )
152 159
     .await
153 160
     .unwrap();
154 161
 
155
-    let mut mike_sg = create_account(
162
+    let mike_sg = create_account(
156 163
         &client,
157
-        &mut validator,
164
+        &validator,
158 165
         "mike.test.near",
159 166
         near_units::near::parse("10 N").unwrap(),
160 167
     )
@@ -162,9 +169,9 @@ async fn key_exchange() {
162 169
     .unwrap();
163 170
 
164 171
     // Create an contract account
165
-    let mut contract_sg = create_account(
172
+    let contract_sg = create_account(
166 173
         &client,
167
-        &mut validator,
174
+        &validator,
168 175
         "contract.test.near",
169 176
         near_units::near::parse("200 N").unwrap(),
170 177
     )
@@ -176,8 +183,8 @@ async fn key_exchange() {
176 183
     let contract_id = contract_sg.account().clone();
177 184
 
178 185
     client
179
-        .deploy_contract(&mut contract_sg, &contract_id, contract_wasm)
180
-        .commit_empty()
186
+        .deploy_contract(&contract_sg, &contract_id, contract_wasm)
187
+        .commit(Finality::Final)
181 188
         .await
182 189
         .unwrap();
183 190
 
@@ -190,7 +197,7 @@ async fn key_exchange() {
190 197
     .unwrap();
191 198
 
192 199
     // Create provisioners for each user
193
-    let keypair_str = alice_sg.secret_key().to_string();
200
+    let keypair_str = alice_sg.secret_key().string();
194 201
     let provisioner = KeyProvisioner::new(
195 202
         keypair_str,
196 203
         alice_sg.nonce(),
@@ -220,7 +227,7 @@ async fn key_exchange() {
220 227
         .unwrap();
221 228
 
222 229
     // Then each user push own key to blockchain
223
-    let keypair_str = bob_sg.secret_key().to_string();
230
+    let keypair_str = bob_sg.secret_key().string();
224 231
     let provisioner_bob = KeyProvisioner::new(
225 232
         keypair_str,
226 233
         bob_sg.nonce(),
@@ -233,7 +240,7 @@ async fn key_exchange() {
233 240
         .await
234 241
         .unwrap();
235 242
 
236
-    let keypair_str = karl_sg.secret_key().to_string();
243
+    let keypair_str = karl_sg.secret_key().string();
237 244
     let provisioner_karl = KeyProvisioner::new(
238 245
         keypair_str,
239 246
         karl_sg.nonce(),
@@ -246,7 +253,7 @@ async fn key_exchange() {
246 253
         .await
247 254
         .unwrap();
248 255
 
249
-    let keypair_str = mike_sg.secret_key().to_string();
256
+    let keypair_str = mike_sg.secret_key().string();
250 257
     let provisioner_mike = KeyProvisioner::new(
251 258
         keypair_str,
252 259
         mike_sg.nonce(),
@@ -290,19 +297,19 @@ async fn key_exchange() {
290 297
         .all(|key| key == alice_key));
291 298
 
292 299
     // delete all accounts
293
-    delete_account(&client, &mut contract_sg, validator.account())
300
+    delete_account(&client, &contract_sg, validator.account())
294 301
         .await
295 302
         .unwrap();
296
-    delete_account(&client, &mut alice_sg, validator.account())
303
+    delete_account(&client, &alice_sg, validator.account())
297 304
         .await
298 305
         .unwrap();
299
-    delete_account(&client, &mut bob_sg, validator.account())
306
+    delete_account(&client, &bob_sg, validator.account())
300 307
         .await
301 308
         .unwrap();
302
-    delete_account(&client, &mut karl_sg, validator.account())
309
+    delete_account(&client, &karl_sg, validator.account())
303 310
         .await
304 311
         .unwrap();
305
-    delete_account(&client, &mut mike_sg, validator.account())
312
+    delete_account(&client, &mike_sg, validator.account())
306 313
         .await
307 314
         .unwrap();
308 315
 }

Loading…
Cancel
Save