iota_rest_api/client/
mod.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5pub mod sdk;
6
7use iota_sdk2::types::EpochId;
8use iota_types::{
9    TypeTag,
10    base_types::{IotaAddress, ObjectID, SequenceNumber},
11    crypto::AuthorityStrongQuorumSignInfo,
12    effects::{TransactionEffects, TransactionEvents},
13    full_checkpoint_content::CheckpointData,
14    messages_checkpoint::{CertifiedCheckpointSummary, CheckpointSequenceNumber},
15    object::Object,
16    transaction::Transaction,
17};
18pub use reqwest;
19use sdk::Result;
20
21use self::sdk::Response;
22use crate::transactions::ExecuteTransactionQueryParameters;
23
24#[derive(Clone)]
25pub struct Client {
26    inner: sdk::Client,
27}
28
29impl Client {
30    pub fn new<S: AsRef<str>>(base_url: S) -> Self {
31        Self {
32            inner: sdk::Client::new(base_url.as_ref()).unwrap(),
33        }
34    }
35
36    pub async fn get_latest_checkpoint(&self) -> Result<CertifiedCheckpointSummary> {
37        self.inner
38            .get_latest_checkpoint()
39            .await
40            .map(Response::into_inner)
41            .and_then(|checkpoint| checkpoint.try_into().map_err(Into::into))
42    }
43
44    pub async fn get_full_checkpoint(
45        &self,
46        checkpoint_sequence_number: CheckpointSequenceNumber,
47    ) -> Result<CheckpointData> {
48        let url = self
49            .inner
50            .url()
51            .join(&format!("checkpoints/{checkpoint_sequence_number}/full"))?;
52
53        let response = self
54            .inner
55            .client()
56            .get(url)
57            .header(reqwest::header::ACCEPT, crate::APPLICATION_BCS)
58            .send()
59            .await?;
60
61        self.inner.bcs(response).await.map(Response::into_inner)
62    }
63
64    pub async fn get_checkpoint_summary(
65        &self,
66        checkpoint_sequence_number: CheckpointSequenceNumber,
67    ) -> Result<CertifiedCheckpointSummary> {
68        self.inner
69            .get_checkpoint(checkpoint_sequence_number)
70            .await
71            .map(Response::into_inner)
72            .and_then(|checkpoint| checkpoint.try_into().map_err(Into::into))
73    }
74
75    pub async fn get_object(&self, object_id: ObjectID) -> Result<Object> {
76        self.inner
77            .get_object(object_id.into())
78            .await
79            .map(Response::into_inner)
80            .and_then(|object| object.try_into().map_err(Into::into))
81    }
82
83    pub async fn get_object_with_version(
84        &self,
85        object_id: ObjectID,
86        version: SequenceNumber,
87    ) -> Result<Object> {
88        self.inner
89            .get_object_with_version(object_id.into(), version.into())
90            .await
91            .map(Response::into_inner)
92            .and_then(|object| object.try_into().map_err(Into::into))
93    }
94
95    pub async fn execute_transaction(
96        &self,
97        parameters: &ExecuteTransactionQueryParameters,
98        transaction: &Transaction,
99    ) -> Result<TransactionExecutionResponse> {
100        #[derive(serde::Serialize)]
101        struct SignedTransaction<'a> {
102            transaction: &'a iota_types::transaction::TransactionData,
103            signatures: &'a [iota_types::signature::GenericSignature],
104        }
105
106        let url = self.inner.url().join("transactions")?;
107        let body = bcs::to_bytes(&SignedTransaction {
108            transaction: &transaction.inner().intent_message.value,
109            signatures: &transaction.inner().tx_signatures,
110        })?;
111
112        let response = self
113            .inner
114            .client()
115            .post(url)
116            .query(parameters)
117            .header(reqwest::header::ACCEPT, crate::APPLICATION_BCS)
118            .header(reqwest::header::CONTENT_TYPE, crate::APPLICATION_BCS)
119            .body(body)
120            .send()
121            .await?;
122
123        self.inner.bcs(response).await.map(Response::into_inner)
124    }
125
126    pub async fn get_epoch_last_checkpoint(
127        &self,
128        epoch: EpochId,
129    ) -> Result<CertifiedCheckpointSummary> {
130        self.inner
131            .get_epoch_last_checkpoint(epoch)
132            .await
133            .map(Response::into_inner)
134            .and_then(|checkpoint| checkpoint.try_into().map_err(Into::into))
135    }
136}
137
138#[derive(Debug, serde::Serialize, serde::Deserialize)]
139pub struct TransactionExecutionResponse {
140    pub effects: TransactionEffects,
141
142    pub finality: EffectsFinality,
143    pub events: Option<TransactionEvents>,
144    pub balance_changes: Option<Vec<BalanceChange>>,
145    pub input_objects: Option<Vec<Object>>,
146    pub output_objects: Option<Vec<Object>>,
147}
148
149#[derive(Debug, serde::Serialize, serde::Deserialize)]
150pub enum EffectsFinality {
151    Certified {
152        signature: AuthorityStrongQuorumSignInfo,
153    },
154    Checkpointed {
155        checkpoint: CheckpointSequenceNumber,
156    },
157}
158
159#[derive(PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
160pub struct BalanceChange {
161    /// Owner of the balance change
162    pub address: IotaAddress,
163    /// Type of the Coin
164    pub coin_type: TypeTag,
165    /// The amount indicate the balance value changes,
166    /// negative amount means spending coin value and positive means receiving
167    /// coin value.
168    pub amount: i128,
169}