1use super::common::{AccountType, Blockchain, CustodyType, PageParams, TokenStandard, WalletState};
7
8#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
10pub enum NftStandard {
11 #[serde(rename = "ERC721")]
13 Erc721,
14 #[serde(rename = "ERC1155")]
16 Erc1155,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
21pub enum FtStandard {
22 #[serde(rename = "")]
24 Native,
25 #[serde(rename = "ERC20")]
27 Erc20,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
32pub enum ScaCore {
33 #[serde(rename = "circle_4337_v1")]
35 Circle4337V1,
36 #[serde(rename = "circle_6900_singleowner_v1")]
38 Circle6900SingleownerV1,
39 #[serde(rename = "circle_6900_singleowner_v2")]
41 Circle6900SingleownerV2,
42 #[serde(rename = "circle_6900_singleowner_v3")]
44 Circle6900SingleownerV3,
45}
46
47#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct Token {
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub id: Option<String>,
54 pub blockchain: Blockchain,
56 pub is_native: bool,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub name: Option<String>,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub standard: Option<TokenStandard>,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub decimals: Option<i32>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub symbol: Option<String>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub token_address: Option<String>,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub update_date: Option<String>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub create_date: Option<String>,
79}
80
81#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct Balance {
85 pub amount: String,
87 pub token: Token,
89 pub update_date: String,
91}
92
93#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
95#[serde(rename_all = "camelCase")]
96pub struct WalletMetadata {
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub name: Option<String>,
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub ref_id: Option<String>,
103}
104
105#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct Wallet {
109 pub id: String,
111 pub address: String,
113 pub blockchain: Blockchain,
115 pub create_date: String,
117 pub update_date: String,
119 pub custody_type: CustodyType,
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub name: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub ref_id: Option<String>,
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub state: Option<WalletState>,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub user_id: Option<String>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub wallet_set_id: Option<String>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub initial_public_key: Option<String>,
139 #[serde(skip_serializing_if = "Option::is_none")]
141 pub account_type: Option<AccountType>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub sca_core: Option<ScaCore>,
145 #[serde(skip_serializing_if = "Option::is_none")]
147 pub token_balances: Option<Vec<Balance>>,
148}
149
150#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
152#[serde(rename_all = "camelCase")]
153pub struct WalletsData {
154 pub wallets: Vec<Wallet>,
156}
157
158#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
160pub struct Wallets {
161 pub data: WalletsData,
163}
164
165#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
167#[serde(rename_all = "camelCase")]
168pub struct WalletData {
169 pub wallet: Wallet,
171}
172
173#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
175pub struct WalletResponse {
176 pub data: WalletData,
178}
179
180#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
182#[serde(rename_all = "camelCase")]
183pub struct WalletsWithBalancesData {
184 pub wallets: Vec<Wallet>,
186}
187
188#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
190pub struct WalletsWithBalances {
191 pub data: WalletsWithBalancesData,
193}
194
195#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
197#[serde(rename_all = "camelCase")]
198pub struct BalancesData {
199 pub token_balances: Vec<Balance>,
201}
202
203#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
205pub struct Balances {
206 pub data: BalancesData,
208}
209
210#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
212#[serde(rename_all = "camelCase")]
213pub struct Nft {
214 pub amount: String,
216 pub token: Token,
218 pub update_date: String,
220 #[serde(skip_serializing_if = "Option::is_none")]
222 pub nft_token_id: Option<String>,
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub metadata: Option<String>,
226}
227
228#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
230pub struct NftsData {
231 pub nfts: Vec<Nft>,
233}
234
235#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
237pub struct Nfts {
238 pub data: NftsData,
240}
241
242#[derive(Debug, Clone, serde::Serialize)]
244#[serde(rename_all = "camelCase")]
245pub struct CreateWalletsRequest {
246 pub idempotency_key: String,
248 pub entity_secret_ciphertext: String,
250 pub wallet_set_id: String,
252 pub blockchains: Vec<Blockchain>,
254 #[serde(skip_serializing_if = "Option::is_none")]
256 pub account_type: Option<AccountType>,
257 #[serde(skip_serializing_if = "Option::is_none")]
259 pub count: Option<u32>,
260 #[serde(skip_serializing_if = "Option::is_none")]
262 pub metadata: Option<Vec<WalletMetadata>>,
263}
264
265#[derive(Debug, Clone, Default, serde::Serialize)]
267#[serde(rename_all = "camelCase")]
268pub struct UpdateWalletRequest {
269 #[serde(skip_serializing_if = "Option::is_none")]
271 pub name: Option<String>,
272 #[serde(skip_serializing_if = "Option::is_none")]
274 pub ref_id: Option<String>,
275}
276
277#[derive(Debug, Default, Clone, serde::Serialize)]
279#[serde(rename_all = "camelCase")]
280pub struct ListWalletsParams {
281 #[serde(skip_serializing_if = "Option::is_none")]
283 pub blockchain: Option<Blockchain>,
284 #[serde(skip_serializing_if = "Option::is_none")]
286 pub address: Option<String>,
287 #[serde(skip_serializing_if = "Option::is_none")]
289 pub wallet_set_id: Option<String>,
290 #[serde(skip_serializing_if = "Option::is_none")]
292 pub ref_id: Option<String>,
293 #[serde(skip_serializing_if = "Option::is_none")]
295 pub state: Option<WalletState>,
296 #[serde(skip_serializing_if = "Option::is_none")]
298 pub custody_type: Option<CustodyType>,
299 #[serde(flatten)]
301 pub page: PageParams,
302}
303
304#[derive(Debug, Default, Clone, serde::Serialize)]
306#[serde(rename_all = "camelCase")]
307pub struct ListWalletBalancesParams {
308 #[serde(skip_serializing_if = "Option::is_none")]
310 pub include_all: Option<bool>,
311 #[serde(skip_serializing_if = "Option::is_none")]
313 pub name: Option<String>,
314 #[serde(skip_serializing_if = "Option::is_none")]
316 pub token_address: Option<String>,
317 #[serde(skip_serializing_if = "Option::is_none")]
319 pub blockchain: Option<Blockchain>,
320 #[serde(skip_serializing_if = "Option::is_none")]
322 pub wallet_set_id: Option<String>,
323 #[serde(skip_serializing_if = "Option::is_none")]
325 pub wallet_ids: Option<String>,
326 #[serde(skip_serializing_if = "Option::is_none")]
328 pub custody_type: Option<CustodyType>,
329 #[serde(skip_serializing_if = "Option::is_none")]
331 pub address: Option<String>,
332 #[serde(flatten)]
334 pub page: PageParams,
335}
336
337#[derive(Debug, Default, Clone, serde::Serialize)]
339#[serde(rename_all = "camelCase")]
340pub struct WalletNftsParams {
341 #[serde(flatten)]
343 pub page: PageParams,
344}
345
346#[derive(Debug, Default, Clone, serde::Serialize)]
348#[serde(rename_all = "camelCase")]
349pub struct ListWalletNftsParams {
350 #[serde(skip_serializing_if = "Option::is_none")]
352 pub standard: Option<NftStandard>,
353 #[serde(skip_serializing_if = "Option::is_none")]
355 pub name: Option<String>,
356 #[serde(skip_serializing_if = "Option::is_none")]
358 pub token_address: Option<String>,
359 #[serde(flatten)]
361 pub page: PageParams,
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367
368 #[test]
369 fn wallet_response_deserializes() -> Result<(), Box<dyn std::error::Error>> {
370 let json = r#"{
371 "data": {
372 "wallet": {
373 "id": "wallet-id-1",
374 "address": "0x1234",
375 "blockchain": "ETH",
376 "createDate": "2024-01-01T00:00:00Z",
377 "updateDate": "2024-01-01T00:00:00Z",
378 "custodyType": "DEVELOPER",
379 "state": "LIVE"
380 }
381 }
382 }"#;
383 let resp: WalletResponse = serde_json::from_str(json)?;
384 assert_eq!(resp.data.wallet.id, "wallet-id-1");
385 assert_eq!(resp.data.wallet.blockchain, Blockchain::Eth);
386 assert_eq!(resp.data.wallet.state, Some(WalletState::Live));
387 Ok(())
388 }
389
390 #[test]
391 fn wallets_response_deserializes() -> Result<(), Box<dyn std::error::Error>> {
392 let json = r#"{
393 "data": {
394 "wallets": [
395 {
396 "id": "w1",
397 "address": "0xabc",
398 "blockchain": "MATIC",
399 "createDate": "2024-01-01T00:00:00Z",
400 "updateDate": "2024-01-01T00:00:00Z",
401 "custodyType": "DEVELOPER"
402 }
403 ]
404 }
405 }"#;
406 let resp: Wallets = serde_json::from_str(json)?;
407 assert_eq!(resp.data.wallets.len(), 1);
408 assert_eq!(resp.data.wallets[0].blockchain, Blockchain::Matic);
409 Ok(())
410 }
411
412 #[test]
413 fn nfts_response_deserializes() -> Result<(), Box<dyn std::error::Error>> {
414 let json = r#"{
415 "data": {
416 "nfts": [
417 {
418 "amount": "1",
419 "token": {
420 "blockchain": "BASE",
421 "isNative": false
422 },
423 "updateDate": "2024-01-01T00:00:00Z",
424 "nftTokenId": "42"
425 }
426 ]
427 }
428 }"#;
429 let resp: Nfts = serde_json::from_str(json)?;
430 assert_eq!(resp.data.nfts.len(), 1);
431 assert_eq!(resp.data.nfts[0].nft_token_id.as_deref(), Some("42"));
432 Ok(())
433 }
434
435 #[test]
436 fn sca_core_serializes() -> Result<(), Box<dyn std::error::Error>> {
437 let json = serde_json::to_string(&ScaCore::Circle4337V1)?;
438 assert_eq!(json, "\"circle_4337_v1\"");
439 let back: ScaCore = serde_json::from_str(&json)?;
440 assert_eq!(back, ScaCore::Circle4337V1);
441 Ok(())
442 }
443
444 #[test]
445 fn create_wallets_request_serializes() -> Result<(), Box<dyn std::error::Error>> {
446 let req = CreateWalletsRequest {
447 idempotency_key: "key".to_string(),
448 entity_secret_ciphertext: "cipher".to_string(),
449 wallet_set_id: "set-id".to_string(),
450 blockchains: vec![Blockchain::Eth],
451 account_type: None,
452 count: Some(2),
453 metadata: None,
454 };
455 let json = serde_json::to_string(&req)?;
456 assert!(json.contains("walletSetId"));
457 assert!(json.contains("\"ETH\""));
458 Ok(())
459 }
460}