magiclink_server_wallets_api/
core_api.rs1use crate::{
2 domain::{
3 MessageSigning,
4 Signing,
5 SolanaSignMessage,
6 Wallet,
7 WalletGroup,
8 },
9 dto::{
10 ApiResponse,
11 BitcoinPayload,
12 EVMPayload,
13 MessageSigningParam,
14 RecoveryParam,
15 SolanaPayload,
16 SolanaSignMessageParam,
17 TransSigningParam,
18 WalletGroupMetadataParam,
19 WalletParam,
20 },
21};
22use reqwest::header::{
23 HeaderMap,
24 HeaderValue,
25};
26use reqwest_middleware::{
27 ClientBuilder,
28 ClientWithMiddleware,
29 Error,
30};
31use reqwest_tracing::TracingMiddleware;
32use std::{
33 env,
34 future::Future,
35};
36
37static BASE_URI: &str = "https://tee.magiclabs.com/v1/api";
38
39pub struct CoreApi {
40 client: ClientWithMiddleware,
41 api_secret: String,
42}
43
44impl Default for CoreApi {
45 fn default() -> Self {
46 dotenv::dotenv().ok();
47
48 let client: ClientWithMiddleware = ClientBuilder::new(reqwest::Client::new())
49 .with(TracingMiddleware::default())
50 .build();
51
52 let api_secret = env::var("MAGIC_LINK_API_SECRET").expect("MAGIC_LINK_API_SECRET is missing");
53
54 Self { client, api_secret }
55 }
56}
57
58impl CoreApi {
59 pub fn new(client: ClientWithMiddleware, api_secret: String) -> Self {
60 Self { client, api_secret }
61 }
62
63 fn default_headers(&self) -> HeaderMap {
64 let mut headers = HeaderMap::new();
65 headers.append(
66 "content-type",
67 HeaderValue::from_str("application/json").expect("Expect applicaton/json as content-type"),
68 );
69 headers.append(
70 "x-magic-secret-key",
71 HeaderValue::from_str(self.api_secret.as_str()).expect("Set api secret to header"),
72 );
73 headers
74 }
75}
76
77trait WalletApi {
78 fn create_wallet_group(
79 &self,
80 metadata: &WalletGroupMetadataParam,
81 ) -> impl Future<Output = Result<ApiResponse<WalletGroup>, Error>>;
82 fn wallet_group_list(&self) -> impl Future<Output = Result<ApiResponse<Vec<WalletGroup>>, Error>>;
83 fn create_wallet(&self, wallet_param: &WalletParam) -> impl Future<Output = Result<ApiResponse<Wallet>, Error>>;
84 fn recover_wallet(&self, recovery_param: &RecoveryParam) -> impl Future<Output = Result<ApiResponse<Wallet>, Error>>;
85}
86
87trait SigningApi {
88 fn evm_transaction_signing(
89 &self,
90 trans_sign_param: &TransSigningParam<EVMPayload>,
91 ) -> impl Future<Output = Result<ApiResponse<Signing>, Error>>;
92 fn solana_transaction_signing(
93 &self,
94 trans_sign_param: &TransSigningParam<SolanaPayload>,
95 ) -> impl Future<Output = Result<ApiResponse<Signing>, Error>>;
96 fn bitcoin_transaction_signing(
97 &self,
98 trans_sign_param: &TransSigningParam<BitcoinPayload>,
99 ) -> impl Future<Output = Result<ApiResponse<Signing>, Error>>;
100
101 fn message_signing(
102 &self,
103 message_sign_param: &MessageSigningParam,
104 ) -> impl Future<Output = Result<ApiResponse<MessageSigning>, Error>>;
105 fn solana_message_signing(
106 &self,
107 solana_sign_message_param: &SolanaSignMessageParam,
108 ) -> impl Future<Output = Result<ApiResponse<SolanaSignMessage>, Error>>;
109}
110
111impl WalletApi for CoreApi {
112 async fn create_wallet_group(&self, metadata: &WalletGroupMetadataParam) -> Result<ApiResponse<WalletGroup>, Error> {
113 let url: String = format!("{}/wallet_group", BASE_URI);
114 self
115 .client
116 .post(url)
117 .headers(self.default_headers())
118 .json(metadata)
119 .send()
120 .await?
121 .json::<ApiResponse<WalletGroup>>()
122 .await
123 .map_err(|e| Error::Reqwest(e))
124 }
125
126 async fn wallet_group_list(&self) -> Result<ApiResponse<Vec<WalletGroup>>, Error> {
127 let url: String = format!("{}/wallet_groups", BASE_URI);
128 self
129 .client
130 .get(url)
131 .headers(self.default_headers())
132 .send()
133 .await?
134 .json::<ApiResponse<Vec<WalletGroup>>>()
135 .await
136 .map_err(|e| Error::Reqwest(e))
137 }
138
139 async fn create_wallet(&self, wallet_param: &WalletParam) -> Result<ApiResponse<Wallet>, Error> {
140 let url: String = format!("{}/wallet", BASE_URI);
141 self
142 .client
143 .post(url)
144 .headers(self.default_headers())
145 .json(wallet_param)
146 .send()
147 .await?
148 .json::<ApiResponse<Wallet>>()
149 .await
150 .map_err(|e| Error::Reqwest(e))
151 }
152
153 async fn recover_wallet(&self, recovery_param: &RecoveryParam) -> Result<ApiResponse<Wallet>, Error> {
154 let url: String = format!("{}/wallet/recovery/confirm", BASE_URI);
155 self
156 .client
157 .post(url)
158 .headers(self.default_headers())
159 .json(recovery_param)
160 .send()
161 .await?
162 .json::<ApiResponse<Wallet>>()
163 .await
164 .map_err(|e| Error::Reqwest(e))
165 }
166}
167
168impl SigningApi for CoreApi {
169 async fn evm_transaction_signing(
170 &self,
171 evm_sign_param: &TransSigningParam<EVMPayload>,
172 ) -> Result<ApiResponse<Signing>, Error> {
173 let url = format!("{}/wallet/sign_transaction", BASE_URI);
174 self
175 .client
176 .post(url)
177 .headers(self.default_headers())
178 .json(evm_sign_param)
179 .send()
180 .await?
181 .json::<ApiResponse<Signing>>()
182 .await
183 .map_err(|e| Error::Reqwest(e))
184 }
185
186 async fn solana_transaction_signing(
187 &self,
188 solana_sign_param: &TransSigningParam<SolanaPayload>,
189 ) -> Result<ApiResponse<Signing>, Error> {
190 let url = format!("{}/wallet/sign_transaction", BASE_URI);
191 self
192 .client
193 .post(url)
194 .headers(self.default_headers())
195 .json(solana_sign_param)
196 .send()
197 .await?
198 .json::<ApiResponse<Signing>>()
199 .await
200 .map_err(|e| Error::Reqwest(e))
201 }
202
203 async fn bitcoin_transaction_signing(
204 &self,
205 bitcoin_sign_param: &TransSigningParam<BitcoinPayload>,
206 ) -> Result<ApiResponse<Signing>, Error> {
207 let url = format!("{}/wallet/sign_transaction", BASE_URI);
208 self
209 .client
210 .post(url)
211 .headers(self.default_headers())
212 .json(bitcoin_sign_param)
213 .send()
214 .await?
215 .json::<ApiResponse<Signing>>()
216 .await
217 .map_err(|e| Error::Reqwest(e))
218 }
219
220 async fn message_signing(
221 &self,
222 message_sign_param: &MessageSigningParam,
223 ) -> Result<ApiResponse<MessageSigning>, Error> {
224 let url = format!("{}/wallet/sign_data", BASE_URI);
225 self
226 .client
227 .post(url)
228 .headers(self.default_headers())
229 .json(message_sign_param)
230 .send()
231 .await?
232 .json::<ApiResponse<MessageSigning>>()
233 .await
234 .map_err(|e| Error::Reqwest(e))
235 }
236
237 async fn solana_message_signing(
238 &self,
239 solana_sign_message_param: &SolanaSignMessageParam,
240 ) -> Result<ApiResponse<SolanaSignMessage>, Error> {
241 let url = format!("{}/wallet/svm/sign_message", BASE_URI);
242 self
243 .client
244 .post(url)
245 .headers(self.default_headers())
246 .json(solana_sign_message_param)
247 .send()
248 .await?
249 .json::<ApiResponse<SolanaSignMessage>>()
250 .await
251 .map_err(|e| Error::Reqwest(e))
252 }
253}