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(
66 &self,
67 amount: &BigInt,
68 depth: u8,
69 label: Option<&str>,
70 ) -> Result<BatchId, Error> {
71 let opts = label.map(|l| PostageBatchOptions {
72 label: Some(l.to_string()),
73 ..Default::default()
74 });
75 self.create_postage_batch_with_options(amount, depth, opts.as_ref())
76 .await
77 }
78
79 pub async fn create_postage_batch_with_options(
84 &self,
85 amount: &BigInt,
86 depth: u8,
87 opts: Option<&PostageBatchOptions>,
88 ) -> Result<BatchId, Error> {
89 let path = format!("stamps/{amount}/{depth}");
90 let mut builder = request(&self.inner, Method::POST, &path)?;
91 if let Some(o) = opts {
92 let mut query: Vec<(&str, String)> = Vec::new();
93 if let Some(l) = &o.label {
94 query.push(("label", l.clone()));
95 }
96 if let Some(im) = o.immutable {
97 query.push(("immutable", im.to_string()));
98 }
99 if !query.is_empty() {
100 let q: Vec<(&str, &str)> = query.iter().map(|(k, v)| (*k, v.as_str())).collect();
101 builder = builder.query(&q);
102 }
103 if let Some(gp) = &o.gas_price {
104 builder = builder.header("Gas-Price", gp);
105 }
106 if let Some(gl) = &o.gas_limit {
107 builder = builder.header("Gas-Limit", gl);
108 }
109 }
110 let res: BatchIdResp = self.inner.send_json(builder).await?;
111 BatchId::from_hex(&res.batch_id)
112 }
113
114 pub async fn top_up_batch(&self, batch_id: &BatchId, amount: &BigInt) -> Result<(), Error> {
116 let path = format!("stamps/topup/{}/{amount}", batch_id.to_hex());
117 let builder = request(&self.inner, Method::PATCH, &path)?;
118 self.inner.send(builder).await?;
119 Ok(())
120 }
121
122 pub async fn dilute_batch(&self, batch_id: &BatchId, depth: u8) -> Result<(), Error> {
124 let path = format!("stamps/dilute/{}/{depth}", batch_id.to_hex());
125 let builder = request(&self.inner, Method::PATCH, &path)?;
126 self.inner.send(builder).await?;
127 Ok(())
128 }
129}