Skip to main content

hanzo_client/apis/
wallet_api.rs

1/*
2 * Hanzo Cloud API
3 *
4 * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator's admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
5 *
6 * The version of the OpenAPI document: v1
7 * 
8 * Generated by: https://openapi-generator.tech
9 */
10
11
12use reqwest;
13use serde::{Deserialize, Serialize, de::Error as _};
14use crate::{apis::ResponseContent, models};
15use super::{Error, configuration, ContentType};
16
17
18/// struct for typed errors of method [`get_wallet`]
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(untagged)]
21pub enum GetWalletError {
22    UnknownValue(serde_json::Value),
23}
24
25/// struct for typed errors of method [`get_wallet_accounts`]
26#[derive(Debug, Clone, Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum GetWalletAccountsError {
29    UnknownValue(serde_json::Value),
30}
31
32/// struct for typed errors of method [`get_wallet_by_id`]
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(untagged)]
35pub enum GetWalletByIdError {
36    UnknownValue(serde_json::Value),
37}
38
39/// struct for typed errors of method [`post_wallet`]
40#[derive(Debug, Clone, Serialize, Deserialize)]
41#[serde(untagged)]
42pub enum PostWalletError {
43    UnknownValue(serde_json::Value),
44}
45
46/// struct for typed errors of method [`post_wallet_accounts`]
47#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(untagged)]
49pub enum PostWalletAccountsError {
50    UnknownValue(serde_json::Value),
51}
52
53/// struct for typed errors of method [`post_wallet_by_id_keys`]
54#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(untagged)]
56pub enum PostWalletByIdKeysError {
57    UnknownValue(serde_json::Value),
58}
59
60/// struct for typed errors of method [`post_wallet_by_id_sign`]
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(untagged)]
63pub enum PostWalletByIdSignError {
64    UnknownValue(serde_json::Value),
65}
66
67/// struct for typed errors of method [`post_wallet_by_id_transactions`]
68#[derive(Debug, Clone, Serialize, Deserialize)]
69#[serde(untagged)]
70pub enum PostWalletByIdTransactionsError {
71    UnknownValue(serde_json::Value),
72}
73
74
75/// Returns the caller org's wallets, newest first, optionally NARROWED within the org by project, agent or account. The org is always the bound isolation boundary — the filters only ever narrow inside it, so a caller can never widen past its own org.
76pub async fn get_wallet(configuration: &configuration::Configuration, project: Option<&str>, agent: Option<&str>, account: Option<&str>) -> Result<models::WalletList, Error<GetWalletError>> {
77    // add a prefix to parameters to efficiently prevent name collisions
78    let p_project = project;
79    let p_agent = agent;
80    let p_account = account;
81
82    let uri_str = format!("{}/v1/wallet", configuration.base_path);
83    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
84
85    if let Some(ref param_value) = p_project {
86        req_builder = req_builder.query(&[("project", &param_value.to_string())]);
87    }
88    if let Some(ref param_value) = p_agent {
89        req_builder = req_builder.query(&[("agent", &param_value.to_string())]);
90    }
91    if let Some(ref param_value) = p_account {
92        req_builder = req_builder.query(&[("account", &param_value.to_string())]);
93    }
94    if let Some(ref user_agent) = configuration.user_agent {
95        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
96    }
97    if let Some(ref token) = configuration.bearer_access_token {
98        req_builder = req_builder.bearer_auth(token.to_owned());
99    };
100
101    let req = req_builder.build()?;
102    let resp = configuration.client.execute(req).await?;
103
104    let status = resp.status();
105    let content_type = resp
106        .headers()
107        .get("content-type")
108        .and_then(|v| v.to_str().ok())
109        .unwrap_or("application/octet-stream");
110    let content_type = super::ContentType::from(content_type);
111
112    if !status.is_client_error() && !status.is_server_error() {
113        let content = resp.text().await?;
114        match content_type {
115            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
116            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::WalletList`"))),
117            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::WalletList`")))),
118        }
119    } else {
120        let content = resp.text().await?;
121        let entity: Option<GetWalletError> = serde_json::from_str(&content).ok();
122        Err(Error::ResponseError(ResponseContent { status, content, entity }))
123    }
124}
125
126/// Returns the caller org's wallet accounts, newest first. Accounts are physically org-scoped, so another tenant's are not reachable from here.
127pub async fn get_wallet_accounts(configuration: &configuration::Configuration, ) -> Result<models::AccountList, Error<GetWalletAccountsError>> {
128
129    let uri_str = format!("{}/v1/wallet/accounts", configuration.base_path);
130    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
131
132    if let Some(ref user_agent) = configuration.user_agent {
133        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
134    }
135    if let Some(ref token) = configuration.bearer_access_token {
136        req_builder = req_builder.bearer_auth(token.to_owned());
137    };
138
139    let req = req_builder.build()?;
140    let resp = configuration.client.execute(req).await?;
141
142    let status = resp.status();
143    let content_type = resp
144        .headers()
145        .get("content-type")
146        .and_then(|v| v.to_str().ok())
147        .unwrap_or("application/octet-stream");
148    let content_type = super::ContentType::from(content_type);
149
150    if !status.is_client_error() && !status.is_server_error() {
151        let content = resp.text().await?;
152        match content_type {
153            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
154            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::AccountList`"))),
155            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::AccountList`")))),
156        }
157    } else {
158        let content = resp.text().await?;
159        let entity: Option<GetWalletAccountsError> = serde_json::from_str(&content).ok();
160        Err(Error::ResponseError(ResponseContent { status, content, entity }))
161    }
162}
163
164/// Returns one of the caller org's wallets: its scope, custody kind, tier, chain and on-chain address. The custody handle to the signing material is never part of the answer. A wallet id another org owns reads as not found, so the response cannot confirm that it exists.
165pub async fn get_wallet_by_id(configuration: &configuration::Configuration, id: &str) -> Result<models::Wallet, Error<GetWalletByIdError>> {
166    // add a prefix to parameters to efficiently prevent name collisions
167    let p_id = id;
168
169    let uri_str = format!("{}/v1/wallet/{id}", configuration.base_path, id=crate::apis::urlencode(p_id));
170    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
171
172    if let Some(ref user_agent) = configuration.user_agent {
173        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
174    }
175    if let Some(ref token) = configuration.bearer_access_token {
176        req_builder = req_builder.bearer_auth(token.to_owned());
177    };
178
179    let req = req_builder.build()?;
180    let resp = configuration.client.execute(req).await?;
181
182    let status = resp.status();
183    let content_type = resp
184        .headers()
185        .get("content-type")
186        .and_then(|v| v.to_str().ok())
187        .unwrap_or("application/octet-stream");
188    let content_type = super::ContentType::from(content_type);
189
190    if !status.is_client_error() && !status.is_server_error() {
191        let content = resp.text().await?;
192        match content_type {
193            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
194            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::Wallet`"))),
195            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::Wallet`")))),
196        }
197    } else {
198        let content = resp.text().await?;
199        let entity: Option<GetWalletByIdError> = serde_json::from_str(&content).ok();
200        Err(Error::ResponseError(ResponseContent { status, content, entity }))
201    }
202}
203
204/// Provisions a new signing identity under one of the caller org's accounts and answers the stored wallet including its on-chain address. The custody backend generates the key material — a KMS-sealed secp256k1 key, an MPC threshold key on the ring, or a Safe smart wallet owned by one — and the HANDLE to it is kept server-side and never returned. A custody kind the deployment has not wired fails CLOSED with 503: a signature is never fabricated. The wallet is scoped to the org, the caller's ambient project, and optionally an agent and the named account; those narrowings are what its key ref is derived from, so each must be a url-safe segment.
205pub async fn post_wallet(configuration: &configuration::Configuration, create_wallet_in: models::CreateWalletIn) -> Result<models::Wallet, Error<PostWalletError>> {
206    // add a prefix to parameters to efficiently prevent name collisions
207    let p_create_wallet_in = create_wallet_in;
208
209    let uri_str = format!("{}/v1/wallet", configuration.base_path);
210    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
211
212    if let Some(ref user_agent) = configuration.user_agent {
213        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
214    }
215    if let Some(ref token) = configuration.bearer_access_token {
216        req_builder = req_builder.bearer_auth(token.to_owned());
217    };
218    req_builder = req_builder.json(&p_create_wallet_in);
219
220    let req = req_builder.build()?;
221    let resp = configuration.client.execute(req).await?;
222
223    let status = resp.status();
224    let content_type = resp
225        .headers()
226        .get("content-type")
227        .and_then(|v| v.to_str().ok())
228        .unwrap_or("application/octet-stream");
229    let content_type = super::ContentType::from(content_type);
230
231    if !status.is_client_error() && !status.is_server_error() {
232        let content = resp.text().await?;
233        match content_type {
234            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
235            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::Wallet`"))),
236            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::Wallet`")))),
237        }
238    } else {
239        let content = resp.text().await?;
240        let entity: Option<PostWalletError> = serde_json::from_str(&content).ok();
241        Err(Error::ResponseError(ResponseContent { status, content, entity }))
242    }
243}
244
245/// Opens a named wallet account for the caller's org. An account is a GROUPING of wallets, not a key or a balance: wallets are created under one and can be listed by it. The org is stamped by the server from the validated principal, so a request can never open an account in another tenant.
246pub async fn post_wallet_accounts(configuration: &configuration::Configuration, create_account_in: models::CreateAccountIn) -> Result<models::WalletAccount, Error<PostWalletAccountsError>> {
247    // add a prefix to parameters to efficiently prevent name collisions
248    let p_create_account_in = create_account_in;
249
250    let uri_str = format!("{}/v1/wallet/accounts", configuration.base_path);
251    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
252
253    if let Some(ref user_agent) = configuration.user_agent {
254        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
255    }
256    if let Some(ref token) = configuration.bearer_access_token {
257        req_builder = req_builder.bearer_auth(token.to_owned());
258    };
259    req_builder = req_builder.json(&p_create_account_in);
260
261    let req = req_builder.build()?;
262    let resp = configuration.client.execute(req).await?;
263
264    let status = resp.status();
265    let content_type = resp
266        .headers()
267        .get("content-type")
268        .and_then(|v| v.to_str().ok())
269        .unwrap_or("application/octet-stream");
270    let content_type = super::ContentType::from(content_type);
271
272    if !status.is_client_error() && !status.is_server_error() {
273        let content = resp.text().await?;
274        match content_type {
275            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
276            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::WalletAccount`"))),
277            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::WalletAccount`")))),
278        }
279    } else {
280        let content = resp.text().await?;
281        let entity: Option<PostWalletAccountsError> = serde_json::from_str(&content).ok();
282        Err(Error::ResponseError(ResponseContent { status, content, entity }))
283    }
284}
285
286/// Rolls one wallet's signing material through its own custody backend and answers the wallet with whatever address that produced. For KMS custody a fresh secp256k1 key is generated and sealed, which CHANGES the address — funds and approvals at the old address do not move. For a Safe the address is counterfactual and the owner shares are ring-managed, so rotation is a no-op and the address is unchanged. A backend that is not configured fails closed with 503 rather than leaving the wallet half-rotated.
287pub async fn post_wallet_by_id_keys(configuration: &configuration::Configuration, id: &str) -> Result<models::Wallet, Error<PostWalletByIdKeysError>> {
288    // add a prefix to parameters to efficiently prevent name collisions
289    let p_id = id;
290
291    let uri_str = format!("{}/v1/wallet/{id}/keys", configuration.base_path, id=crate::apis::urlencode(p_id));
292    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
293
294    if let Some(ref user_agent) = configuration.user_agent {
295        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
296    }
297    if let Some(ref token) = configuration.bearer_access_token {
298        req_builder = req_builder.bearer_auth(token.to_owned());
299    };
300
301    let req = req_builder.build()?;
302    let resp = configuration.client.execute(req).await?;
303
304    let status = resp.status();
305    let content_type = resp
306        .headers()
307        .get("content-type")
308        .and_then(|v| v.to_str().ok())
309        .unwrap_or("application/octet-stream");
310    let content_type = super::ContentType::from(content_type);
311
312    if !status.is_client_error() && !status.is_server_error() {
313        let content = resp.text().await?;
314        match content_type {
315            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
316            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::Wallet`"))),
317            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::Wallet`")))),
318        }
319    } else {
320        let content = resp.text().await?;
321        let entity: Option<PostWalletByIdKeysError> = serde_json::from_str(&content).ok();
322        Err(Error::ResponseError(ResponseContent { status, content, entity }))
323    }
324}
325
326/// Produces a secp256k1 signature from one of the caller org's wallets over a 32-byte digest, through whichever custody backend that wallet uses. Give it either a `digest` (32 bytes as hex, signed verbatim) or a `message` (hashed with Keccak256 first) — exactly one is required. The private key never leaves its backend: KMS custody opens the sealed key in-process, MPC custody produces a threshold signature on the ring. The answer carries the digest that was signed alongside the signature, so a caller can verify what it got.
327pub async fn post_wallet_by_id_sign(configuration: &configuration::Configuration, id: &str, sign_in: models::SignIn) -> Result<models::Signature, Error<PostWalletByIdSignError>> {
328    // add a prefix to parameters to efficiently prevent name collisions
329    let p_id = id;
330    let p_sign_in = sign_in;
331
332    let uri_str = format!("{}/v1/wallet/{id}/sign", configuration.base_path, id=crate::apis::urlencode(p_id));
333    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
334
335    if let Some(ref user_agent) = configuration.user_agent {
336        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
337    }
338    if let Some(ref token) = configuration.bearer_access_token {
339        req_builder = req_builder.bearer_auth(token.to_owned());
340    };
341    req_builder = req_builder.json(&p_sign_in);
342
343    let req = req_builder.build()?;
344    let resp = configuration.client.execute(req).await?;
345
346    let status = resp.status();
347    let content_type = resp
348        .headers()
349        .get("content-type")
350        .and_then(|v| v.to_str().ok())
351        .unwrap_or("application/octet-stream");
352    let content_type = super::ContentType::from(content_type);
353
354    if !status.is_client_error() && !status.is_server_error() {
355        let content = resp.text().await?;
356        match content_type {
357            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
358            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::Signature`"))),
359            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::Signature`")))),
360        }
361    } else {
362        let content = resp.text().await?;
363        let entity: Option<PostWalletByIdSignError> = serde_json::from_str(&content).ok();
364        Err(Error::ResponseError(ResponseContent { status, content, entity }))
365    }
366}
367
368/// Composes a Safe transaction on the MPC ring and answers its EIP-712 hash together with the owner approval the ring's threshold signature produced. Only a wallet whose custody is \"safe\" can do this — any other custody is a 400, because the backend itself is asked whether it can propose rather than the kind being switched on. The ring computes the Safe-tx hash bound to the Safe contract and the chain id, so the hash a caller gets back is the one the Safe will verify. This PROPOSES: it does not execute the transaction.
369pub async fn post_wallet_by_id_transactions(configuration: &configuration::Configuration, id: &str, safe_tx_in: models::SafeTxIn) -> Result<models::SafeProposal, Error<PostWalletByIdTransactionsError>> {
370    // add a prefix to parameters to efficiently prevent name collisions
371    let p_id = id;
372    let p_safe_tx_in = safe_tx_in;
373
374    let uri_str = format!("{}/v1/wallet/{id}/transactions", configuration.base_path, id=crate::apis::urlencode(p_id));
375    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
376
377    if let Some(ref user_agent) = configuration.user_agent {
378        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
379    }
380    if let Some(ref token) = configuration.bearer_access_token {
381        req_builder = req_builder.bearer_auth(token.to_owned());
382    };
383    req_builder = req_builder.json(&p_safe_tx_in);
384
385    let req = req_builder.build()?;
386    let resp = configuration.client.execute(req).await?;
387
388    let status = resp.status();
389    let content_type = resp
390        .headers()
391        .get("content-type")
392        .and_then(|v| v.to_str().ok())
393        .unwrap_or("application/octet-stream");
394    let content_type = super::ContentType::from(content_type);
395
396    if !status.is_client_error() && !status.is_server_error() {
397        let content = resp.text().await?;
398        match content_type {
399            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
400            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::SafeProposal`"))),
401            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::SafeProposal`")))),
402        }
403    } else {
404        let content = resp.text().await?;
405        let entity: Option<PostWalletByIdTransactionsError> = serde_json::from_str(&content).ok();
406        Err(Error::ResponseError(ResponseContent { status, content, entity }))
407    }
408}
409