1use std::collections::HashMap;
2
3use serde::Deserialize;
4
5#[derive(Clone, Debug, Deserialize)]
6pub struct ExplorerResponse {
7 pub listings: HashMap<String, WalletData>,
8 pub count: u32,
9 pub total: u32,
10}
11
12impl ExplorerResponse {
13 pub fn parse_wallets(&self, project_id: &str) -> Vec<WalletDescription> {
14 let mut wallets: Vec<WalletDescription> = Vec::new();
15 for wallet in self.listings.values() {
16 if let Ok(mut w) = TryInto::<WalletDescription>::try_into(wallet) {
17 w.project_id = project_id.to_string();
18 wallets.push(w)
19 }
20 }
21 wallets
22 }
23}
24
25#[derive(Clone, Debug, Deserialize)]
26pub struct WalletData {
27 pub id: String,
28 pub name: String,
29 pub chains: Vec<String>,
30 pub image_id: String,
31 pub mobile: Option<LinkSet>,
32 pub desktop: Option<LinkSet>,
33 pub metadata: WalletMetadata,
34}
35
36pub enum ExplorerError {
37 BadWallet,
38}
39
40impl TryInto<WalletDescription> for &WalletData {
41 type Error = ExplorerError;
42
43 fn try_into(self) -> Result<WalletDescription, Self::Error> {
44 let chains =
45 self.chains
46 .iter()
47 .filter_map(|c| {
48 if c.starts_with("eip155:") {
49 c[6..].parse::<u64>().ok()
50 } else {
51 None
52 }
53 })
54 .collect::<Vec<_>>();
55 let mobile_schema = match &self.mobile {
56 None => None,
57 Some(l) => match &l.native {
58 Some(url) => {
59 if !url.is_empty() {
60 Some(url.clone())
61 } else {
62 None
63 }
64 }
65 None => None,
66 },
67 };
68 let desktop_schema = match &self.desktop {
69 None => None,
70 Some(l) => match &l.native {
71 Some(url) => {
72 if !url.is_empty() {
73 Some(url.clone())
74 } else {
75 None
76 }
77 }
78 None => None,
79 },
80 };
81
82 if mobile_schema.is_none() && desktop_schema.is_none() {
83 return Err(ExplorerError::BadWallet);
84 }
85
86 Ok(WalletDescription {
87 id: self.id.clone(),
88 short_name: self.metadata.short_name.clone().unwrap_or(self.name.clone()),
89 name: self.name.clone(),
90 chains,
91 image_id: self.image_id.clone(),
92 project_id: "".to_owned(),
93 desktop_schema,
94 mobile_schema,
95 })
96 }
97}
98
99#[derive(Clone, Debug, Deserialize)]
100pub struct LinkSet {
101 pub native: Option<String>,
102 pub universal: Option<String>,
103}
104
105#[derive(Clone, Debug, Deserialize)]
106#[serde(rename_all = "camelCase")]
107pub struct WalletMetadata {
108 pub short_name: Option<String>,
109}
110
111pub enum ImageSize {
112 Small,
113 Medium,
114 Large,
115}
116
117#[derive(Clone, Debug, PartialEq)]
118pub struct WalletDescription {
119 pub id: String,
120 pub short_name: String,
121 pub name: String,
122 pub chains: Vec<u64>,
123 pub image_id: String,
124 pub project_id: String,
125 pub desktop_schema: Option<String>,
126 pub mobile_schema: Option<String>,
127}
128
129impl WalletDescription {
130 pub fn get_image(&self, size: ImageSize) -> String {
131 let size_mark = match size {
132 ImageSize::Small => "sm",
133 ImageSize::Medium => "md",
134 ImageSize::Large => "lg",
135 };
136 format!(
137 "https://explorer-api.walletconnect.com/v3/logo/{size_mark}/{}?projectId={}",
138 self.image_id, self.project_id
139 )
140 }
141}