|
@@ -9,8 +9,8 @@ use crate::{
|
9
|
9
|
types::{
|
10
|
10
|
crypto::{ED25519PublicKey, ED25519Signature, Keypair},
|
11
|
11
|
near::{
|
12
|
|
- Action, Chunks, FinalExecutionOutcomeView, FinalExecutionStatus, FunctionCallAction,
|
13
|
|
- SignedTransaction, Transaction, ViewResult,
|
|
12
|
+ Action, Chunks, DeployContractAction, FinalExecutionOutcomeView, FinalExecutionStatus,
|
|
13
|
+ FunctionCallAction, SignedTransaction, Transaction, ViewResult,
|
14
|
14
|
},
|
15
|
15
|
},
|
16
|
16
|
Error,
|
|
@@ -118,24 +118,42 @@ impl NearClient {
|
118
|
118
|
serde_json::from_slice(&view_result.result).map_err(Error::DeserializeTxResp)
|
119
|
119
|
}
|
120
|
120
|
|
121
|
|
- pub fn call<'a>(
|
|
121
|
+ pub fn function_call<'a>(
|
122
|
122
|
&'a self,
|
123
|
123
|
signer: &'a mut Signer,
|
124
|
124
|
contract_id: &'a AccountId,
|
125
|
125
|
method: &'static str,
|
126
|
|
- ) -> TransactionBuilder {
|
127
|
|
- TransactionBuilder::new(self, signer, method, contract_id)
|
|
126
|
+ ) -> FunctionCallBuilder {
|
|
127
|
+ let transaction_info = TransactionInfo::new(self, signer, contract_id);
|
|
128
|
+ FunctionCallBuilder::new(transaction_info, method)
|
|
129
|
+ }
|
|
130
|
+
|
|
131
|
+ pub fn deploy_contract<'a>(
|
|
132
|
+ &'a self,
|
|
133
|
+ signer: &'a mut Signer,
|
|
134
|
+ contract_id: &'a AccountId,
|
|
135
|
+ wasm: Vec<u8>,
|
|
136
|
+ ) -> Call {
|
|
137
|
+ let transaction_info = TransactionInfo::new(self, signer, contract_id);
|
|
138
|
+
|
|
139
|
+ Call {
|
|
140
|
+ transaction_info,
|
|
141
|
+ action: Action::from(DeployContractAction { code: wasm }),
|
|
142
|
+ }
|
128
|
143
|
}
|
129
|
144
|
}
|
130
|
145
|
|
131
|
|
-pub struct Call<'a>(TransactionBuilder<'a>);
|
|
146
|
+pub struct Call<'a> {
|
|
147
|
+ transaction_info: TransactionInfo<'a>,
|
|
148
|
+ action: Action,
|
|
149
|
+}
|
132
|
150
|
|
133
|
151
|
impl<'a> Call<'a> {
|
134
|
152
|
pub async fn commit<T: DeserializeOwned>(self) -> Result<T> {
|
135
|
|
- let transaction_bytes = serialize_transaction(&self.0).await?;
|
|
153
|
+ let transaction_bytes = serialize_transaction(&self.transaction_info, self.action).await?;
|
136
|
154
|
|
137
|
155
|
let execution_outcome = self
|
138
|
|
- .0
|
|
156
|
+ .transaction_info
|
139
|
157
|
.client
|
140
|
158
|
.rpc_client
|
141
|
159
|
.request::<FinalExecutionOutcomeView>(
|
|
@@ -151,7 +169,7 @@ impl<'a> Call<'a> {
|
151
|
169
|
match execution_outcome.status {
|
152
|
170
|
FinalExecutionStatus::Failure(err) => Err(Error::TransactionExec(err)),
|
153
|
171
|
FinalExecutionStatus::SuccessValue(data) => {
|
154
|
|
- self.0.signer.key_nonce += 1;
|
|
172
|
+ self.transaction_info.signer.key_nonce += 1;
|
155
|
173
|
serde_json::from_slice::<T>(&data).map_err(Error::DeserializeTxResp)
|
156
|
174
|
}
|
157
|
175
|
_ => Err(Error::TxNotStarted),
|
|
@@ -159,8 +177,8 @@ impl<'a> Call<'a> {
|
159
|
177
|
}
|
160
|
178
|
|
161
|
179
|
pub async fn commit_async(self) -> Result<String> {
|
162
|
|
- let transaction_bytes = serialize_transaction(&self.0).await?;
|
163
|
|
- self.0
|
|
180
|
+ let transaction_bytes = serialize_transaction(&self.transaction_info, self.action).await?;
|
|
181
|
+ self.transaction_info
|
164
|
182
|
.client
|
165
|
183
|
.rpc_client
|
166
|
184
|
.request::<String>(
|
|
@@ -175,31 +193,62 @@ impl<'a> Call<'a> {
|
175
|
193
|
}
|
176
|
194
|
}
|
177
|
195
|
|
178
|
|
-pub struct TransactionBuilder<'a> {
|
|
196
|
+pub struct TransactionInfo<'a> {
|
179
|
197
|
client: &'a NearClient,
|
180
|
198
|
signer: &'a mut Signer,
|
181
|
|
- method: &'static str,
|
182
|
199
|
contract_id: &'a AccountId,
|
|
200
|
+}
|
|
201
|
+impl<'a> TransactionInfo<'a> {
|
|
202
|
+ fn new(client: &'a NearClient, signer: &'a mut Signer, contract_id: &'a AccountId) -> Self {
|
|
203
|
+ Self {
|
|
204
|
+ client,
|
|
205
|
+ signer,
|
|
206
|
+ contract_id,
|
|
207
|
+ }
|
|
208
|
+ }
|
|
209
|
+}
|
|
210
|
+
|
|
211
|
+async fn serialize_transaction<'a>(
|
|
212
|
+ transaction_info: &'a TransactionInfo<'_>,
|
|
213
|
+ action: Action,
|
|
214
|
+) -> Result<Vec<u8>> {
|
|
215
|
+ let block_hash = transaction_info.client.block().await?;
|
|
216
|
+
|
|
217
|
+ let transaction = Transaction {
|
|
218
|
+ signer_id: transaction_info.signer.account().clone(),
|
|
219
|
+ public_key: transaction_info.signer.public_key(),
|
|
220
|
+ nonce: transaction_info.signer.nonce() + 1,
|
|
221
|
+ receiver_id: transaction_info.contract_id.clone(),
|
|
222
|
+ block_hash,
|
|
223
|
+ actions: vec![action],
|
|
224
|
+ };
|
|
225
|
+
|
|
226
|
+ let signed_transaction = sign_transaction(transaction_info.signer, transaction);
|
|
227
|
+ borsh::to_vec(&signed_transaction).map_err(Error::TransactionSerialize)
|
|
228
|
+}
|
|
229
|
+
|
|
230
|
+fn sign_transaction(signer: &Signer, transaction: Transaction) -> SignedTransaction {
|
|
231
|
+ let (hash, ..) = transaction.get_hash_and_size();
|
|
232
|
+ let signature = signer.keypair.sign(hash.0.as_ref());
|
|
233
|
+ SignedTransaction::new(signature, transaction)
|
|
234
|
+}
|
|
235
|
+
|
|
236
|
+pub struct FunctionCallBuilder<'a> {
|
|
237
|
+ transaction_info: TransactionInfo<'a>,
|
183
|
238
|
deposit: Balance,
|
184
|
239
|
gas: Gas,
|
185
|
240
|
args: Option<Value>,
|
|
241
|
+ method_name: &'a str,
|
186
|
242
|
}
|
187
|
243
|
|
188
|
|
-impl<'a> TransactionBuilder<'a> {
|
189
|
|
- fn new(
|
190
|
|
- client: &'a NearClient,
|
191
|
|
- signer: &'a mut Signer,
|
192
|
|
- method: &'static str,
|
193
|
|
- contract_id: &'a AccountId,
|
194
|
|
- ) -> Self {
|
|
244
|
+impl<'a> FunctionCallBuilder<'a> {
|
|
245
|
+ fn new(transaction_info: TransactionInfo<'a>, method_name: &'a str) -> Self {
|
195
|
246
|
Self {
|
196
|
|
- client,
|
197
|
|
- signer,
|
198
|
|
- contract_id,
|
199
|
|
- method,
|
200
|
|
- deposit: Default::default(),
|
|
247
|
+ transaction_info,
|
|
248
|
+ method_name,
|
201
|
249
|
gas: Default::default(),
|
202
|
250
|
args: Default::default(),
|
|
251
|
+ deposit: Default::default(),
|
203
|
252
|
}
|
204
|
253
|
}
|
205
|
254
|
|
|
@@ -218,41 +267,28 @@ impl<'a> TransactionBuilder<'a> {
|
218
|
267
|
self
|
219
|
268
|
}
|
220
|
269
|
|
221
|
|
- pub fn build(self) -> Call<'a> {
|
222
|
|
- Call(self)
|
|
270
|
+ pub fn build(self) -> Result<Call<'a>> {
|
|
271
|
+ let args = self
|
|
272
|
+ .args
|
|
273
|
+ .as_ref()
|
|
274
|
+ .map(serde_json::to_vec)
|
|
275
|
+ .transpose()
|
|
276
|
+ .map_err(Error::ArgsSerialize)?
|
|
277
|
+ .unwrap_or_default();
|
|
278
|
+
|
|
279
|
+ let action = Action::from(FunctionCallAction {
|
|
280
|
+ method_name: self.method_name.to_string(),
|
|
281
|
+ args,
|
|
282
|
+ gas: self.gas,
|
|
283
|
+ deposit: self.deposit,
|
|
284
|
+ });
|
|
285
|
+
|
|
286
|
+ Ok(Call {
|
|
287
|
+ transaction_info: self.transaction_info,
|
|
288
|
+ action,
|
|
289
|
+ })
|
223
|
290
|
}
|
224
|
291
|
}
|
225
|
292
|
|
226
|
|
-async fn serialize_transaction<'a>(builder: &TransactionBuilder<'a>) -> Result<Vec<u8>> {
|
227
|
|
- let block_hash = builder.client.block().await?;
|
228
|
|
- let args_bytes = builder
|
229
|
|
- .args
|
230
|
|
- .as_ref()
|
231
|
|
- .map(serde_json::to_vec)
|
232
|
|
- .transpose()
|
233
|
|
- .map_err(Error::ArgsSerialize)?
|
234
|
|
- .unwrap_or_default();
|
235
|
|
-
|
236
|
|
- let transaction = Transaction {
|
237
|
|
- signer_id: builder.signer.account().clone(),
|
238
|
|
- public_key: builder.signer.public_key(),
|
239
|
|
- nonce: builder.signer.nonce() + 1,
|
240
|
|
- receiver_id: builder.contract_id.clone(),
|
241
|
|
- block_hash,
|
242
|
|
- actions: vec![Action::FunctionCall(FunctionCallAction {
|
243
|
|
- method_name: builder.method.to_owned(),
|
244
|
|
- args: args_bytes,
|
245
|
|
- gas: builder.gas,
|
246
|
|
- deposit: builder.deposit,
|
247
|
|
- })],
|
248
|
|
- };
|
249
|
|
-
|
250
|
|
- let (hash, ..) = transaction.get_hash_and_size();
|
251
|
|
- let signature = builder.signer.keypair.sign(hash.0.as_ref());
|
252
|
|
- let signed_transaction = SignedTransaction::new(signature, transaction);
|
253
|
|
-
|
254
|
|
- borsh::to_vec(&signed_transaction).map_err(Error::TransactionSerialize)
|
255
|
|
-}
|
256
|
|
-
|
257
|
293
|
#[cfg(test)]
|
258
|
294
|
mod tests {}
|