1mod types;
8
9use crate::{
10 contract_client::*,
11 types as sdk_types,
12 v2::{self, IntoBlockIdentifier},
13};
14use concordium_base::{
15 base::Energy,
16 contracts_common::{Address, Amount},
17 transactions::{AccountTransaction, EncodedPayload},
18};
19use sdk_types::{smart_contracts, transactions};
20use smart_contracts::concordium_contracts_common;
21use std::convert::From;
22use thiserror::*;
23pub use types::*;
24
25#[derive(Debug, Clone, Copy)]
26pub enum Cis2Type {}
29
30pub type Cis2Contract = ContractClient<Cis2Type>;
38
39#[derive(Debug, Error)]
42pub enum Cis2TransactionError {
43 #[error("Invalid receive name: {0}")]
45 InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
46
47 #[error("Invalid transfer parameter: {0}")]
49 InvalidTransferParams(#[from] NewTransferParamsError),
50
51 #[error("Invalid updateOperator parameter: {0}")]
53 InvalidUpdateOperatorParams(#[from] NewUpdateOperatorParamsError),
54
55 #[error("RPC error: {0}")]
57 RPCError(#[from] crate::endpoints::RPCError),
58}
59
60#[derive(Debug, Error)]
63pub enum Cis2DryRunError {
64 #[error("Invalid receive name: {0}")]
66 InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
67
68 #[error("Invalid transfer parameter: {0}")]
70 InvalidTransferParams(#[from] NewTransferParamsError),
71
72 #[error("Invalid updateOperator parameter: {0}")]
74 InvalidUpdateOperatorParams(#[from] NewUpdateOperatorParamsError),
75
76 #[error("RPC error: {0}")]
78 QueryError(#[from] crate::endpoints::QueryError),
79
80 #[error("Rejected by the node: {0:?}.")]
82 NodeRejected(v2::Upward<sdk_types::RejectReason>),
83}
84
85#[derive(Debug, Error)]
88pub enum Cis2QueryError {
89 #[error("Invalid receive name: {0}")]
91 InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
92
93 #[error("Invalid balanceOf parameter: {0}")]
95 InvalidBalanceOfParams(#[from] NewBalanceOfQueryParamsError),
96
97 #[error("Invalid operatorOf parameter: {0}")]
99 InvalidOperatorOfParams(#[from] NewOperatorOfQueryParamsError),
100
101 #[error("Invalid tokenMetadata parameter: {0}")]
103 InvalidTokenMetadataParams(#[from] NewTokenMetadataQueryParamsError),
104
105 #[error("RPC error: {0}")]
107 RPCError(#[from] super::v2::QueryError),
108
109 #[error("Failed parsing the response.")]
111 ResponseParseError(#[from] concordium_contracts_common::ParseError),
112
113 #[error("Rejected by the node: {0:?}.")]
115 NodeRejected(v2::Upward<sdk_types::RejectReason>),
116}
117
118impl From<v2::Upward<sdk_types::RejectReason>> for Cis2QueryError {
121 fn from(err: v2::Upward<sdk_types::RejectReason>) -> Self {
122 Self::NodeRejected(err)
123 }
124}
125impl From<sdk_types::RejectReason> for Cis2QueryError {
126 fn from(err: sdk_types::RejectReason) -> Self {
127 Self::NodeRejected(v2::Upward::Known(err))
128 }
129}
130
131impl From<v2::Upward<sdk_types::RejectReason>> for Cis2DryRunError {
134 fn from(err: v2::Upward<sdk_types::RejectReason>) -> Self {
135 Self::NodeRejected(err)
136 }
137}
138impl From<sdk_types::RejectReason> for Cis2DryRunError {
139 fn from(err: sdk_types::RejectReason) -> Self {
140 Self::NodeRejected(v2::Upward::Known(err))
141 }
142}
143
144pub type Cis2TransactionMetadata = ContractTransactionMetadata;
146
147impl Cis2Contract {
148 pub async fn transfer_dry_run(
159 &mut self,
160 bi: impl IntoBlockIdentifier,
161 sender: Address,
162 transfers: Vec<Transfer>,
163 ) -> Result<Energy, Cis2DryRunError> {
164 let parameter = TransferParams::new(transfers)?;
165 let parameter = smart_contracts::OwnedParameter::from_serial(¶meter)
166 .map_err(|_| Cis2DryRunError::InvalidTransferParams(NewTransferParamsError))?;
167 let ir = self
168 .invoke_raw::<Cis2DryRunError>("transfer", Amount::zero(), Some(sender), parameter, bi)
169 .await?;
170 match ir {
171 smart_contracts::InvokeContractResult::Success { used_energy, .. } => Ok(used_energy),
172 smart_contracts::InvokeContractResult::Failure { reason, .. } => Err(reason.into()),
173 }
174 }
175
176 pub async fn transfer_single_dry_run(
179 &mut self,
180 bi: impl IntoBlockIdentifier,
181 sender: Address,
182 transfer: Transfer,
183 ) -> Result<Energy, Cis2DryRunError> {
184 self.transfer_dry_run(bi, sender, vec![transfer]).await
185 }
186
187 pub async fn transfer(
198 &mut self,
199 signer: &impl transactions::ExactSizeTransactionSigner,
200 transaction_metadata: Cis2TransactionMetadata,
201 transfers: Vec<Transfer>,
202 ) -> Result<sdk_types::hashes::TransactionHash, Cis2TransactionError> {
203 let transfer = self.make_transfer(signer, transaction_metadata, transfers)?;
204 let hash = self.client.send_account_transaction(transfer).await?;
205 Ok(hash)
206 }
207
208 pub fn make_transfer(
219 &self,
220 signer: &impl transactions::ExactSizeTransactionSigner,
221 transaction_metadata: Cis2TransactionMetadata,
222 transfers: Vec<Transfer>,
223 ) -> Result<AccountTransaction<EncodedPayload>, Cis2TransactionError> {
224 let parameter = TransferParams::new(transfers)?;
225 let message = smart_contracts::OwnedParameter::from_serial(¶meter)
226 .map_err(|_| Cis2TransactionError::InvalidTransferParams(NewTransferParamsError))?;
227 self.make_update_raw(signer, &transaction_metadata, "transfer", message)
228 }
229
230 pub async fn transfer_single(
233 &mut self,
234 signer: &impl transactions::ExactSizeTransactionSigner,
235 transaction_metadata: Cis2TransactionMetadata,
236 transfer: Transfer,
237 ) -> Result<sdk_types::hashes::TransactionHash, Cis2TransactionError> {
238 self.transfer(signer, transaction_metadata, vec![transfer])
239 .await
240 }
241
242 pub fn make_transfer_single(
245 &self,
246 signer: &impl transactions::ExactSizeTransactionSigner,
247 transaction_metadata: Cis2TransactionMetadata,
248 transfer: Transfer,
249 ) -> Result<AccountTransaction<EncodedPayload>, Cis2TransactionError> {
250 self.make_transfer(signer, transaction_metadata, vec![transfer])
251 }
252
253 pub async fn update_operator_dry_run(
264 &mut self,
265 bi: impl IntoBlockIdentifier,
266 owner: Address,
267 updates: Vec<UpdateOperator>,
268 ) -> anyhow::Result<Energy, Cis2DryRunError> {
269 let parameter = UpdateOperatorParams::new(updates)?;
270 let parameter = smart_contracts::OwnedParameter::from_serial(¶meter)
271 .map_err(|_| Cis2DryRunError::InvalidTransferParams(NewTransferParamsError))?;
272 let ir = self
273 .invoke_raw::<Cis2DryRunError>(
274 "updateOperator",
275 Amount::zero(),
276 Some(owner),
277 parameter,
278 bi,
279 )
280 .await?;
281 match ir {
282 smart_contracts::InvokeContractResult::Success { used_energy, .. } => Ok(used_energy),
283 smart_contracts::InvokeContractResult::Failure { reason, .. } => Err(reason.into()),
284 }
285 }
286
287 pub async fn update_operator_single_dry_run(
290 &mut self,
291 bi: impl IntoBlockIdentifier,
292 owner: Address,
293 operator: Address,
294 update: OperatorUpdate,
295 ) -> anyhow::Result<Energy, Cis2DryRunError> {
296 self.update_operator_dry_run(bi, owner, vec![UpdateOperator { update, operator }])
297 .await
298 }
299
300 pub fn make_update_operator(
311 &self,
312 signer: &impl transactions::ExactSizeTransactionSigner,
313 transaction_metadata: Cis2TransactionMetadata,
314 updates: Vec<UpdateOperator>,
315 ) -> anyhow::Result<AccountTransaction<EncodedPayload>, Cis2TransactionError> {
316 let parameter = UpdateOperatorParams::new(updates)?;
317 let message = smart_contracts::OwnedParameter::from_serial(¶meter).map_err(|_| {
318 Cis2TransactionError::InvalidUpdateOperatorParams(NewUpdateOperatorParamsError)
319 })?;
320 self.make_update_raw(signer, &transaction_metadata, "updateOperator", message)
321 }
322
323 pub async fn update_operator(
334 &mut self,
335 signer: &impl transactions::ExactSizeTransactionSigner,
336 transaction_metadata: Cis2TransactionMetadata,
337 updates: Vec<UpdateOperator>,
338 ) -> anyhow::Result<sdk_types::hashes::TransactionHash, Cis2TransactionError> {
339 let update = self.make_update_operator(signer, transaction_metadata, updates)?;
340 let hash = self.client.send_account_transaction(update).await?;
341 Ok(hash)
342 }
343
344 pub async fn update_operator_single(
347 &mut self,
348 signer: &impl transactions::ExactSizeTransactionSigner,
349 transaction_metadata: Cis2TransactionMetadata,
350 operator: Address,
351 update: OperatorUpdate,
352 ) -> anyhow::Result<sdk_types::hashes::TransactionHash, Cis2TransactionError> {
353 self.update_operator(
354 signer,
355 transaction_metadata,
356 vec![UpdateOperator { update, operator }],
357 )
358 .await
359 }
360
361 pub fn make_update_operator_single(
364 &self,
365 signer: &impl transactions::ExactSizeTransactionSigner,
366 transaction_metadata: Cis2TransactionMetadata,
367 operator: Address,
368 update: OperatorUpdate,
369 ) -> anyhow::Result<AccountTransaction<EncodedPayload>, Cis2TransactionError> {
370 self.make_update_operator(
371 signer,
372 transaction_metadata,
373 vec![UpdateOperator { update, operator }],
374 )
375 }
376
377 pub async fn balance_of(
388 &mut self,
389 bi: impl IntoBlockIdentifier,
390 queries: Vec<BalanceOfQuery>,
391 ) -> Result<BalanceOfQueryResponse, Cis2QueryError> {
392 let parameter = BalanceOfQueryParams::new(queries)?;
393 let parameter = smart_contracts::OwnedParameter::from_serial(¶meter)
394 .map_err(|_| Cis2QueryError::InvalidBalanceOfParams(NewBalanceOfQueryParamsError))?;
395 self.view_raw("balanceOf", parameter, bi).await
396 }
397
398 pub async fn balance_of_single(
402 &mut self,
403 bi: impl IntoBlockIdentifier,
404 token_id: TokenId,
405 address: Address,
406 ) -> Result<TokenAmount, Cis2QueryError> {
407 let res = self
408 .balance_of(bi, vec![BalanceOfQuery { token_id, address }])
409 .await?;
410 only_one(res)
411 }
412
413 pub async fn operator_of(
424 &mut self,
425 bi: impl IntoBlockIdentifier,
426 queries: Vec<OperatorOfQuery>,
427 ) -> Result<OperatorOfQueryResponse, Cis2QueryError> {
428 let parameter = OperatorOfQueryParams::new(queries)?;
429 let parameter = smart_contracts::OwnedParameter::from_serial(¶meter)
430 .map_err(|_| Cis2QueryError::InvalidOperatorOfParams(NewOperatorOfQueryParamsError))?;
431 self.view_raw("operatorOf", parameter, bi).await
432 }
433
434 pub async fn operator_of_single(
438 &mut self,
439 bi: impl IntoBlockIdentifier,
440 owner: Address,
441 operator: Address,
442 ) -> Result<bool, Cis2QueryError> {
443 let res = self
444 .operator_of(
445 bi,
446 vec![OperatorOfQuery {
447 owner,
448 address: operator,
449 }],
450 )
451 .await?;
452 only_one(res)
453 }
454
455 pub async fn token_metadata(
466 &mut self,
467 bi: impl IntoBlockIdentifier,
468 queries: Vec<TokenId>,
469 ) -> Result<TokenMetadataQueryResponse, Cis2QueryError> {
470 let parameter = TokenMetadataQueryParams::new(queries)?;
471 let parameter = smart_contracts::OwnedParameter::from_serial(¶meter).map_err(|_| {
472 Cis2QueryError::InvalidTokenMetadataParams(NewTokenMetadataQueryParamsError)
473 })?;
474 self.view_raw("tokenMetadata", parameter, bi).await
475 }
476
477 pub async fn token_metadata_single(
481 &mut self,
482 bi: impl IntoBlockIdentifier,
483 token_id: TokenId,
484 ) -> Result<MetadataUrl, Cis2QueryError> {
485 let res = self.token_metadata(bi, vec![token_id]).await?;
486 only_one(res)
487 }
488}
489
490fn only_one<A, V: AsRef<Vec<A>>>(res: V) -> Result<A, Cis2QueryError>
493where
494 Vec<A>: From<V>,
495{
496 let err = Cis2QueryError::ResponseParseError(concordium_contracts_common::ParseError {});
497 if res.as_ref().len() > 1 {
498 Err(err)
499 } else {
500 Vec::from(res).pop().ok_or(err)
501 }
502}