use crate::{
contract_client::{ContractClient, ContractTransactionMetadata},
types::{self as sdk_types, transactions},
v2::{self, IntoBlockIdentifier},
};
use concordium_base::{
base::Energy,
cis3_types::{
NewSupportsPermitQueryParamsError, PermitParams, SupportsPermitQueryParams,
SupportsPermitRepsonse,
},
contracts_common::{Address, Amount, OwnedEntrypointName},
smart_contracts::OwnedParameter,
transactions::{AccountTransaction, EncodedPayload},
};
use sdk_types::smart_contracts;
use smart_contracts::concordium_contracts_common;
use thiserror::Error;
#[derive(Debug, Clone, Copy)]
pub enum Cis3Type {}
pub type Cis3Contract = ContractClient<Cis3Type>;
#[derive(Error, Debug)]
pub enum Cis3PermitError {
#[error("Invalid receive name: {0}")]
InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
#[error("RPC error: {0}")]
RPCError(#[from] crate::endpoints::RPCError),
}
#[derive(Error, Debug)]
pub enum Cis3PermitDryRunError {
#[error("Invalid receive name: {0}")]
InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
#[error("RPC error: {0}")]
RPCError(#[from] crate::endpoints::RPCError),
#[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 Cis3SupportsPermitError {
#[error("Invalid receive name: {0}")]
InvalidReceiveName(#[from] concordium_contracts_common::NewReceiveNameError),
#[error("Invalid supportsPermit parameter: {0}")]
InvalidParams(#[from] NewSupportsPermitQueryParamsError),
#[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 Cis3SupportsPermitError {
fn from(err: v2::Upward<sdk_types::RejectReason>) -> Self {
Self::NodeRejected(err)
}
}
impl From<sdk_types::RejectReason> for Cis3SupportsPermitError {
fn from(err: sdk_types::RejectReason) -> Self {
Self::NodeRejected(v2::Upward::Known(err))
}
}
impl From<v2::Upward<sdk_types::RejectReason>> for Cis3PermitDryRunError {
fn from(err: v2::Upward<sdk_types::RejectReason>) -> Self {
Self::NodeRejected(err)
}
}
impl From<sdk_types::RejectReason> for Cis3PermitDryRunError {
fn from(err: sdk_types::RejectReason) -> Self {
Self::NodeRejected(v2::Upward::Known(err))
}
}
impl Cis3Contract {
pub async fn permit_dry_run(
&mut self,
bi: impl IntoBlockIdentifier,
sender: Address,
params: PermitParams,
) -> Result<Energy, Cis3PermitDryRunError> {
let parameter = OwnedParameter::from_serial(¶ms)
.expect("A PermitParams should always be serializable");
let ir = self
.invoke_raw::<Cis3PermitDryRunError>(
"permit",
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 permit(
&mut self,
signer: &impl transactions::ExactSizeTransactionSigner,
metadata: &ContractTransactionMetadata,
params: PermitParams,
) -> Result<sdk_types::hashes::TransactionHash, Cis3PermitError> {
let permit = self.make_permit(signer, metadata, params)?;
let hash = self.client.send_account_transaction(permit).await?;
Ok(hash)
}
pub fn make_permit(
&mut self,
signer: &impl transactions::ExactSizeTransactionSigner,
metadata: &ContractTransactionMetadata,
params: PermitParams,
) -> Result<AccountTransaction<EncodedPayload>, Cis3PermitError> {
let message = smart_contracts::OwnedParameter::from_serial(¶ms)
.expect("A PermitParams should always be serializable");
self.make_update_raw(signer, metadata, "permit", message)
}
pub async fn supports_permit(
&mut self,
bi: impl IntoBlockIdentifier,
entrypoints: Vec<OwnedEntrypointName>,
) -> Result<SupportsPermitRepsonse, Cis3SupportsPermitError> {
let parameter = SupportsPermitQueryParams::new(entrypoints)?;
let message = OwnedParameter::from_serial(¶meter).map_err(|_| {
Cis3SupportsPermitError::InvalidParams(NewSupportsPermitQueryParamsError)
})?;
self.view_raw("supportsPermit", message, bi).await
}
pub async fn supports_permit_single(
&mut self,
bi: impl IntoBlockIdentifier,
entrypoint: OwnedEntrypointName,
) -> Result<bool, Cis3SupportsPermitError> {
only_one(self.supports_permit(bi, vec![entrypoint]).await?)
}
}
fn only_one<A, V: AsRef<Vec<A>>>(res: V) -> Result<A, Cis3SupportsPermitError>
where
Vec<A>: From<V>,
{
let err =
Cis3SupportsPermitError::ResponseParseError(concordium_contracts_common::ParseError {});
if res.as_ref().len() > 1 {
Err(err)
} else {
Vec::from(res).pop().ok_or(err)
}
}