1use num_bigint::BigInt;
4use reqwest::Method;
5use serde::Deserialize;
6
7use crate::api::PostageBatchOptions;
8use crate::client::request;
9use crate::swarm::{BatchId, Error};
10
11use super::PostageApi;
12use super::types::{GlobalPostageBatch, PostageBatch, PostageBatchBuckets};
13
14#[derive(Deserialize)]
15struct StampsResp {
16 stamps: Vec<PostageBatch>,
17}
18
19#[derive(Deserialize)]
20struct BatchesResp {
21 batches: Vec<GlobalPostageBatch>,
22}
23
24#[derive(Deserialize)]
25struct BatchIdResp {
26 #[serde(rename = "batchID")]
27 batch_id: String,
28}
29
30impl PostageApi {
31 pub async fn get_postage_batches(&self) -> Result<Vec<PostageBatch>, Error> {
33 let builder = request(&self.inner, Method::GET, "stamps")?;
34 let res: StampsResp = self.inner.send_json(builder).await?;
35 Ok(res.stamps)
36 }
37
38 pub async fn get_postage_batch(&self, batch_id: &BatchId) -> Result<PostageBatch, Error> {
40 let path = format!("stamps/{}", batch_id.to_hex());
41 let builder = request(&self.inner, Method::GET, &path)?;
42 self.inner.send_json(builder).await
43 }
44
45 pub async fn get_postage_batch_buckets(
47 &self,
48 batch_id: &BatchId,
49 ) -> Result<PostageBatchBuckets, Error> {
50 let path = format!("stamps/{}/buckets", batch_id.to_hex());
51 let builder = request(&self.inner, Method::GET, &path)?;
52 self.inner.send_json(builder).await
53 }
54
55 pub async fn get_global_postage_batches(&self) -> Result<Vec<GlobalPostageBatch>, Error> {
58 let builder = request(&self.inner, Method::GET, "batches")?;
59 let res: BatchesResp = self.inner.send_json(builder).await?;
60 Ok(res.batches)
61 }
62
63 pub async fn create_postage_batch(
88 &self,
89 amount: &BigInt,
90 depth: u8,
91 label: Option<&str>,
92 ) -> Result<BatchId, Error> {
93 let opts = label.map(|l| PostageBatchOptions {
94 label: Some(l.to_string()),
95 ..Default::default()
96 });
97 self.create_postage_batch_with_options(amount, depth, opts.as_ref())
98 .await
99 }
100
101 pub async fn create_postage_batch_with_options(
106 &self,
107 amount: &BigInt,
108 depth: u8,
109 opts: Option<&PostageBatchOptions>,
110 ) -> Result<BatchId, Error> {
111 let path = format!("stamps/{amount}/{depth}");
112 let mut builder = request(&self.inner, Method::POST, &path)?;
113 if let Some(o) = opts {
114 let mut query: Vec<(&str, String)> = Vec::new();
115 if let Some(l) = &o.label {
116 query.push(("label", l.clone()));
117 }
118 if let Some(im) = o.immutable {
119 query.push(("immutable", im.to_string()));
120 }
121 if !query.is_empty() {
122 let q: Vec<(&str, &str)> = query.iter().map(|(k, v)| (*k, v.as_str())).collect();
123 builder = builder.query(&q);
124 }
125 if let Some(gp) = &o.gas_price {
126 builder = builder.header("Gas-Price", gp);
127 }
128 if let Some(gl) = &o.gas_limit {
129 builder = builder.header("Gas-Limit", gl);
130 }
131 }
132 let res: BatchIdResp = self.inner.send_json(builder).await?;
133 BatchId::from_hex(&res.batch_id)
134 }
135
136 pub async fn top_up_batch(&self, batch_id: &BatchId, amount: &BigInt) -> Result<(), Error> {
138 let path = format!("stamps/topup/{}/{amount}", batch_id.to_hex());
139 let builder = request(&self.inner, Method::PATCH, &path)?;
140 self.inner.send(builder).await?;
141 Ok(())
142 }
143
144 pub async fn dilute_batch(&self, batch_id: &BatchId, depth: u8) -> Result<(), Error> {
146 let path = format!("stamps/dilute/{}/{depth}", batch_id.to_hex());
147 let builder = request(&self.inner, Method::PATCH, &path)?;
148 self.inner.send(builder).await?;
149 Ok(())
150 }
151}