calimero-context-primitives 0.10.0

Core Calimero infrastructure and tools
Documentation
use calimero_context_config::client::env::proxy::ContextProxy;
use calimero_context_config::repr::{ReprBytes, ReprTransmute};
use calimero_context_config::types::{ContextStorageEntry, ProposalId};
use calimero_context_config::{Proposal, ProposalAction};
use calimero_primitives::identity::PublicKey;
use eyre::OptionExt;

use super::ExternalClient;

#[derive(Debug)]
pub struct ExternalProxyClient<'a> {
    client: &'a ExternalClient<'a>,
}

impl ExternalClient<'_> {
    #[must_use]
    pub const fn proxy(&self) -> ExternalProxyClient<'_> {
        ExternalProxyClient { client: self }
    }
}

impl ExternalProxyClient<'_> {
    pub async fn propose(
        &self,
        public_key: &PublicKey,
        proposal_id: &ProposalId,
        actions: Vec<ProposalAction>,
    ) -> eyre::Result<()> {
        let signer_id = public_key.rt().expect("infallible conversion");

        let identity = self
            .client
            .context_client()
            .get_identity(&self.client.context_id, public_key)?
            .ok_or_eyre("identity not found")?;

        let private_key = identity.private_key()?;

        let client = self.client.mutate::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let _ignored = client
            .propose(*proposal_id, signer_id, actions)
            .send(**private_key)
            .await?;

        Ok(())
    }

    pub async fn approve(
        &self,
        public_key: &PublicKey,
        proposal_id: &ProposalId,
    ) -> eyre::Result<()> {
        let signer_id = public_key.rt().expect("infallible conversion");

        let identity = self
            .client
            .context_client()
            .get_identity(&self.client.context_id, public_key)?
            .ok_or_eyre("identity not found")?;

        let private_key = identity.private_key()?;

        let client = self.client.mutate::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let _ignored = client
            .approve(signer_id, *proposal_id)
            .send(**private_key)
            .await?;

        Ok(())
    }

    pub async fn active_proposals(&self) -> eyre::Result<u16> {
        let client = self.client.query::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let proposals = client.get_number_of_active_proposals().await?;

        Ok(proposals)
    }

    pub async fn get_external_proxy_contract(&self) -> eyre::Result<String> {
        Ok(self.client.config.proxy_contract.clone().into_owned())
    }

    pub async fn get_external_value(&self, stored_key: Vec<u8>) -> eyre::Result<Vec<u8>> {
        let client = self.client.query::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let value = client.get_context_value(stored_key).await?;

        Ok(value)
    }

    pub async fn get_proposal(&self, proposal_id: &ProposalId) -> eyre::Result<Option<Proposal>> {
        let client = self.client.query::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let proposal = client.proposal(*proposal_id).await?;

        Ok(proposal)
    }

    pub async fn get_proposal_approvers(
        &self,
        proposal_id: &ProposalId,
    ) -> eyre::Result<impl Iterator<Item = PublicKey>> {
        let client = self.client.query::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let approvers = client.get_proposal_approvers(*proposal_id).await?;

        let approvers = approvers
            .into_iter()
            .map(|identity| identity.as_bytes().into());

        Ok(approvers)
    }

    pub async fn get_proposals(&self, offset: usize, limit: usize) -> eyre::Result<Vec<Proposal>> {
        let client = self.client.query::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let proposals = client.proposals(offset, limit).await?;

        Ok(proposals)
    }

    pub async fn proposal_approvals(&self, proposal_id: &ProposalId) -> eyre::Result<usize> {
        let client = self.client.query::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let approvals = client
            .get_number_of_proposal_approvals(*proposal_id)
            .await?;

        Ok(approvals.num_approvals)
    }

    pub async fn get_external_storage_entries(
        &self,
        offset: usize,
        limit: usize,
    ) -> eyre::Result<Vec<ContextStorageEntry>> {
        let client = self.client.query::<ContextProxy>(
            self.client.config.protocol.as_ref().into(),
            self.client.config.network_id.as_ref().into(),
            self.client.config.proxy_contract.as_ref().into(),
        );

        let entries = client.get_context_storage_entries(offset, limit).await?;

        Ok(entries)
    }
}