blokli-client 0.33.1

Client connector to Blokli
Documentation
use super::{InvalidAddressError, QueryFailedError, Uint64, schema};
use crate::{
    api::ChainAddress,
    errors::{BlokliClientError, ErrorKind},
};

/// Safe selector variant sent to the GraphQL API.
#[derive(cynic::Enum, Clone, Copy, Debug, PartialEq, Eq)]
pub enum SafeSelectorInput {
    /// Select by safe contract address.
    #[cynic(rename = "ADDRESS")]
    Address,
    /// Select by owner address.
    #[cynic(rename = "OWNER")]
    Owner,
    /// Select by the owner's chain key legacy alias.
    #[cynic(rename = "CHAIN_KEY")]
    ChainKey,
    /// Select by registered node address.
    #[cynic(rename = "REGISTERED_NODE")]
    RegisteredNode,
}

#[derive(cynic::QueryVariables, Debug)]
pub struct SafeByVariables {
    pub selector: SafeSelectorInput,
    pub address: String,
}

/// Safe contract indexed by Blokli.
#[derive(cynic::QueryFragment, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct Safe {
    /// Safe contract address encoded as a hex string.
    pub address: String,
    /// Chain key associated with the safe.
    pub chain_key: String,
    /// Owner addresses encoded as hex strings.
    pub owners: Vec<String>,
    /// Module contract address encoded as a hex string.
    pub module_address: String,
    /// Registered node addresses encoded as hex strings.
    pub registered_nodes: Vec<String>,
    /// Safe signature threshold, when reported by the API.
    pub threshold: Option<String>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "QueryRoot", variables = "SafeByVariables")]
pub struct QuerySafeBy {
    #[arguments(selector: $selector, address: $address)]
    pub safe_by: Option<SafeByResult>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "SubscriptionRoot")]
pub struct SubscribeSafeDeployment {
    pub safe_deployed: Safe,
}

#[derive(cynic::QueryVariables, Debug)]
pub struct ModuleAddressVariables {
    pub nonce: Uint64,
    pub owner: String,
    pub safe_address: String,
}

/// Predicted module address returned by Blokli.
#[derive(cynic::QueryFragment, Debug, Clone, PartialEq, Eq)]
pub struct ModuleAddress {
    /// GraphQL concrete type name.
    pub __typename: String,
    /// Predicted module contract address encoded as a hex string.
    pub module_address: String,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "QueryRoot", variables = "ModuleAddressVariables")]
pub struct QueryModuleAddress {
    #[arguments(nonce: $nonce, safeAddress: $safe_address, owner: $owner)]
    pub calculate_module_address: CalculateModuleAddressResult,
}

/// Result union for deprecated single-safe GraphQL fields (`safe`, `safeByChainKey`, `safeByRegisteredNode`).
#[derive(cynic::InlineFragments, Debug)]
pub enum SafeResult {
    Safe(Safe),
    InvalidAddressError(InvalidAddressError),
    QueryFailedError(QueryFailedError),
    #[cynic(fallback)]
    Unknown,
}

impl From<SafeResult> for Result<Option<Safe>, BlokliClientError> {
    fn from(value: SafeResult) -> Self {
        match value {
            SafeResult::Safe(safe) => Ok(Some(safe)),
            SafeResult::InvalidAddressError(e) => Err(e.into()),
            SafeResult::QueryFailedError(e) => Err(e.into()),
            SafeResult::Unknown => Err(ErrorKind::NoData.into()),
        }
    }
}

/// List of safes returned by a safe query.
#[derive(cynic::QueryFragment, Debug, Clone, PartialEq, Eq)]
pub struct SafesList {
    /// Matching safes.
    pub safes: Vec<Safe>,
}

#[derive(cynic::InlineFragments, Debug)]
pub enum SafeByResult {
    SafesList(SafesList),
    InvalidAddressError(InvalidAddressError),
    QueryFailedError(QueryFailedError),
    #[cynic(fallback)]
    Unknown,
}

impl From<SafeByResult> for Result<Vec<Safe>, BlokliClientError> {
    fn from(value: SafeByResult) -> Self {
        match value {
            SafeByResult::SafesList(safes) => Ok(safes.safes),
            SafeByResult::InvalidAddressError(e) => Err(e.into()),
            SafeByResult::QueryFailedError(e) => Err(e.into()),
            SafeByResult::Unknown => Err(ErrorKind::NoData.into()),
        }
    }
}

#[derive(cynic::InlineFragments, Debug)]
pub enum CalculateModuleAddressResult {
    ModuleAddress(ModuleAddress),
    InvalidAddressError(InvalidAddressError),
    QueryFailedError(QueryFailedError),
    #[cynic(fallback)]
    Unknown,
}

impl From<CalculateModuleAddressResult> for Result<ChainAddress, BlokliClientError> {
    fn from(value: CalculateModuleAddressResult) -> Self {
        match value {
            CalculateModuleAddressResult::ModuleAddress(address) => {
                let address = address.module_address.to_lowercase();
                Ok(hex::decode(address.trim_start_matches("0x"))
                    .map_err(|_| BlokliClientError::from(ErrorKind::ParseError))
                    .and_then(|bytes| bytes.try_into().map_err(|_| ErrorKind::ParseError.into()))?)
            }
            CalculateModuleAddressResult::InvalidAddressError(e) => Err(e.into()),
            CalculateModuleAddressResult::QueryFailedError(e) => Err(e.into()),
            CalculateModuleAddressResult::Unknown => Err(ErrorKind::NoData.into()),
        }
    }
}