mod types;
use crate::{
contract_client::*,
types as sdk_types,
v2::{self, IntoBlockIdentifier},
};
use concordium_base::{
base::Energy,
contracts_common::{Address, Amount},
transactions::{AccountTransaction, EncodedPayload},
};
use sdk_types::{smart_contracts, transactions};
use smart_contracts::concordium_contracts_common;
use std::convert::From;
use thiserror::*;
pub use types::*;
#[derive(Debug, Clone, Copy)]
pub enum Cis2Type {}
pub type Cis2Contract = ContractClient<Cis2Type>;
#[derive(Debug, Error)]
pub enum Cis2TransactionError {
#[error("Invalid receive name: {0}")]
InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
#[error("Invalid transfer parameter: {0}")]
InvalidTransferParams(#[from] NewTransferParamsError),
#[error("Invalid updateOperator parameter: {0}")]
InvalidUpdateOperatorParams(#[from] NewUpdateOperatorParamsError),
#[error("RPC error: {0}")]
RPCError(#[from] crate::endpoints::RPCError),
}
#[derive(Debug, Error)]
pub enum Cis2DryRunError {
#[error("Invalid receive name: {0}")]
InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
#[error("Invalid transfer parameter: {0}")]
InvalidTransferParams(#[from] NewTransferParamsError),
#[error("Invalid updateOperator parameter: {0}")]
InvalidUpdateOperatorParams(#[from] NewUpdateOperatorParamsError),
#[error("RPC error: {0}")]
QueryError(#[from] crate::endpoints::QueryError),
#[error("Rejected by the node: {0:?}.")]
NodeRejected(v2::Upward<sdk_types::RejectReason>),
}
#[derive(Debug, Error)]
pub enum Cis2QueryError {
#[error("Invalid receive name: {0}")]
InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
#[error("Invalid balanceOf parameter: {0}")]
InvalidBalanceOfParams(#[from] NewBalanceOfQueryParamsError),
#[error("Invalid operatorOf parameter: {0}")]
InvalidOperatorOfParams(#[from] NewOperatorOfQueryParamsError),
#[error("Invalid tokenMetadata parameter: {0}")]
InvalidTokenMetadataParams(#[from] NewTokenMetadataQueryParamsError),
#[error("RPC error: {0}")]
RPCError(#[from] super::v2::QueryError),
#[error("Failed parsing the response.")]
ResponseParseError(#[from] concordium_contracts_common::ParseError),
#[error("Rejected by the node: {0:?}.")]
NodeRejected(v2::Upward<sdk_types::RejectReason>),
}
impl From<v2::Upward<sdk_types::RejectReason>> for Cis2QueryError {
fn from(err: v2::Upward<sdk_types::RejectReason>) -> Self {
Self::NodeRejected(err)
}
}
impl From<sdk_types::RejectReason> for Cis2QueryError {
fn from(err: sdk_types::RejectReason) -> Self {
Self::NodeRejected(v2::Upward::Known(err))
}
}
impl From<v2::Upward<sdk_types::RejectReason>> for Cis2DryRunError {
fn from(err: v2::Upward<sdk_types::RejectReason>) -> Self {
Self::NodeRejected(err)
}
}
impl From<sdk_types::RejectReason> for Cis2DryRunError {
fn from(err: sdk_types::RejectReason) -> Self {
Self::NodeRejected(v2::Upward::Known(err))
}
}
pub type Cis2TransactionMetadata = ContractTransactionMetadata;
impl Cis2Contract {
pub async fn transfer_dry_run(
&mut self,
bi: impl IntoBlockIdentifier,
sender: Address,
transfers: Vec<Transfer>,
) -> Result<Energy, Cis2DryRunError> {
let parameter = TransferParams::new(transfers)?;
let parameter = smart_contracts::OwnedParameter::from_serial(¶meter)
.map_err(|_| Cis2DryRunError::InvalidTransferParams(NewTransferParamsError))?;
let ir = self
.invoke_raw::<Cis2DryRunError>("transfer", Amount::zero(), Some(sender), parameter, bi)
.await?;
match ir {
smart_contracts::InvokeContractResult::Success { used_energy, .. } => Ok(used_energy),
smart_contracts::InvokeContractResult::Failure { reason, .. } => Err(reason.into()),
}
}
pub async fn transfer_single_dry_run(
&mut self,
bi: impl IntoBlockIdentifier,
sender: Address,
transfer: Transfer,
) -> Result<Energy, Cis2DryRunError> {
self.transfer_dry_run(bi, sender, vec![transfer]).await
}
pub async fn transfer(
&mut self,
signer: &impl transactions::ExactSizeTransactionSigner,
transaction_metadata: Cis2TransactionMetadata,
transfers: Vec<Transfer>,
) -> Result<sdk_types::hashes::TransactionHash, Cis2TransactionError> {
let transfer = self.make_transfer(signer, transaction_metadata, transfers)?;
let hash = self.client.send_account_transaction(transfer).await?;
Ok(hash)
}
pub fn make_transfer(
&self,
signer: &impl transactions::ExactSizeTransactionSigner,
transaction_metadata: Cis2TransactionMetadata,
transfers: Vec<Transfer>,
) -> Result<AccountTransaction<EncodedPayload>, Cis2TransactionError> {
let parameter = TransferParams::new(transfers)?;
let message = smart_contracts::OwnedParameter::from_serial(¶meter)
.map_err(|_| Cis2TransactionError::InvalidTransferParams(NewTransferParamsError))?;
self.make_update_raw(signer, &transaction_metadata, "transfer", message)
}
pub async fn transfer_single(
&mut self,
signer: &impl transactions::ExactSizeTransactionSigner,
transaction_metadata: Cis2TransactionMetadata,
transfer: Transfer,
) -> Result<sdk_types::hashes::TransactionHash, Cis2TransactionError> {
self.transfer(signer, transaction_metadata, vec![transfer])
.await
}
pub fn make_transfer_single(
&self,
signer: &impl transactions::ExactSizeTransactionSigner,
transaction_metadata: Cis2TransactionMetadata,
transfer: Transfer,
) -> Result<AccountTransaction<EncodedPayload>, Cis2TransactionError> {
self.make_transfer(signer, transaction_metadata, vec![transfer])
}
pub async fn update_operator_dry_run(
&mut self,
bi: impl IntoBlockIdentifier,
owner: Address,
updates: Vec<UpdateOperator>,
) -> anyhow::Result<Energy, Cis2DryRunError> {
let parameter = UpdateOperatorParams::new(updates)?;
let parameter = smart_contracts::OwnedParameter::from_serial(¶meter)
.map_err(|_| Cis2DryRunError::InvalidTransferParams(NewTransferParamsError))?;
let ir = self
.invoke_raw::<Cis2DryRunError>(
"updateOperator",
Amount::zero(),
Some(owner),
parameter,
bi,
)
.await?;
match ir {
smart_contracts::InvokeContractResult::Success { used_energy, .. } => Ok(used_energy),
smart_contracts::InvokeContractResult::Failure { reason, .. } => Err(reason.into()),
}
}
pub async fn update_operator_single_dry_run(
&mut self,
bi: impl IntoBlockIdentifier,
owner: Address,
operator: Address,
update: OperatorUpdate,
) -> anyhow::Result<Energy, Cis2DryRunError> {
self.update_operator_dry_run(bi, owner, vec![UpdateOperator { update, operator }])
.await
}
pub fn make_update_operator(
&self,
signer: &impl transactions::ExactSizeTransactionSigner,
transaction_metadata: Cis2TransactionMetadata,
updates: Vec<UpdateOperator>,
) -> anyhow::Result<AccountTransaction<EncodedPayload>, Cis2TransactionError> {
let parameter = UpdateOperatorParams::new(updates)?;
let message = smart_contracts::OwnedParameter::from_serial(¶meter).map_err(|_| {
Cis2TransactionError::InvalidUpdateOperatorParams(NewUpdateOperatorParamsError)
})?;
self.make_update_raw(signer, &transaction_metadata, "updateOperator", message)
}
pub async fn update_operator(
&mut self,
signer: &impl transactions::ExactSizeTransactionSigner,
transaction_metadata: Cis2TransactionMetadata,
updates: Vec<UpdateOperator>,
) -> anyhow::Result<sdk_types::hashes::TransactionHash, Cis2TransactionError> {
let update = self.make_update_operator(signer, transaction_metadata, updates)?;
let hash = self.client.send_account_transaction(update).await?;
Ok(hash)
}
pub async fn update_operator_single(
&mut self,
signer: &impl transactions::ExactSizeTransactionSigner,
transaction_metadata: Cis2TransactionMetadata,
operator: Address,
update: OperatorUpdate,
) -> anyhow::Result<sdk_types::hashes::TransactionHash, Cis2TransactionError> {
self.update_operator(
signer,
transaction_metadata,
vec![UpdateOperator { update, operator }],
)
.await
}
pub fn make_update_operator_single(
&self,
signer: &impl transactions::ExactSizeTransactionSigner,
transaction_metadata: Cis2TransactionMetadata,
operator: Address,
update: OperatorUpdate,
) -> anyhow::Result<AccountTransaction<EncodedPayload>, Cis2TransactionError> {
self.make_update_operator(
signer,
transaction_metadata,
vec![UpdateOperator { update, operator }],
)
}
pub async fn balance_of(
&mut self,
bi: impl IntoBlockIdentifier,
queries: Vec<BalanceOfQuery>,
) -> Result<BalanceOfQueryResponse, Cis2QueryError> {
let parameter = BalanceOfQueryParams::new(queries)?;
let parameter = smart_contracts::OwnedParameter::from_serial(¶meter)
.map_err(|_| Cis2QueryError::InvalidBalanceOfParams(NewBalanceOfQueryParamsError))?;
self.view_raw("balanceOf", parameter, bi).await
}
pub async fn balance_of_single(
&mut self,
bi: impl IntoBlockIdentifier,
token_id: TokenId,
address: Address,
) -> Result<TokenAmount, Cis2QueryError> {
let res = self
.balance_of(bi, vec![BalanceOfQuery { token_id, address }])
.await?;
only_one(res)
}
pub async fn operator_of(
&mut self,
bi: impl IntoBlockIdentifier,
queries: Vec<OperatorOfQuery>,
) -> Result<OperatorOfQueryResponse, Cis2QueryError> {
let parameter = OperatorOfQueryParams::new(queries)?;
let parameter = smart_contracts::OwnedParameter::from_serial(¶meter)
.map_err(|_| Cis2QueryError::InvalidOperatorOfParams(NewOperatorOfQueryParamsError))?;
self.view_raw("operatorOf", parameter, bi).await
}
pub async fn operator_of_single(
&mut self,
bi: impl IntoBlockIdentifier,
owner: Address,
operator: Address,
) -> Result<bool, Cis2QueryError> {
let res = self
.operator_of(
bi,
vec![OperatorOfQuery {
owner,
address: operator,
}],
)
.await?;
only_one(res)
}
pub async fn token_metadata(
&mut self,
bi: impl IntoBlockIdentifier,
queries: Vec<TokenId>,
) -> Result<TokenMetadataQueryResponse, Cis2QueryError> {
let parameter = TokenMetadataQueryParams::new(queries)?;
let parameter = smart_contracts::OwnedParameter::from_serial(¶meter).map_err(|_| {
Cis2QueryError::InvalidTokenMetadataParams(NewTokenMetadataQueryParamsError)
})?;
self.view_raw("tokenMetadata", parameter, bi).await
}
pub async fn token_metadata_single(
&mut self,
bi: impl IntoBlockIdentifier,
token_id: TokenId,
) -> Result<MetadataUrl, Cis2QueryError> {
let res = self.token_metadata(bi, vec![token_id]).await?;
only_one(res)
}
}
fn only_one<A, V: AsRef<Vec<A>>>(res: V) -> Result<A, Cis2QueryError>
where
Vec<A>: From<V>,
{
let err = Cis2QueryError::ResponseParseError(concordium_contracts_common::ParseError {});
if res.as_ref().len() > 1 {
Err(err)
} else {
Vec::from(res).pop().ok_or(err)
}
}