rust_okx/api/finance/api.rs
1use crate::api::finance::internal::CancelRedeemBody;
2use crate::client::OkxClient;
3use crate::error::Error;
4use crate::transport::Transport;
5
6use super::endpoints::*;
7use super::internal::{AmountBody, DaysQuery, NoParams, SetLendingRateBody, optional_ccy};
8use super::requests::*;
9use super::responses::*;
10/// Accessor for OKX finance endpoint groups.
11///
12/// Obtain one via [`OkxClient::finance`](crate::OkxClient::finance).
13pub struct Finance<'a, T> {
14 client: &'a OkxClient<T>,
15}
16
17impl<'a, T: Transport> Finance<'a, T> {
18 pub(crate) fn new(client: &'a OkxClient<T>) -> Self {
19 Self { client }
20 }
21
22 /// Access Savings endpoints.
23 pub fn savings(&self) -> Savings<'_, T> {
24 Savings {
25 client: self.client,
26 }
27 }
28
29 /// Access Staking/DeFi endpoints.
30 pub fn staking_defi(&self) -> StakingDefi<'_, T> {
31 StakingDefi {
32 client: self.client,
33 }
34 }
35
36 /// Access ETH staking endpoints.
37 pub fn eth_staking(&self) -> EthStaking<'_, T> {
38 EthStaking {
39 client: self.client,
40 }
41 }
42
43 /// Access SOL staking endpoints.
44 pub fn sol_staking(&self) -> SolStaking<'_, T> {
45 SolStaking {
46 client: self.client,
47 }
48 }
49
50 /// Access Flexible Loan endpoints.
51 pub fn flexible_loan(&self) -> FlexibleLoan<'_, T> {
52 FlexibleLoan {
53 client: self.client,
54 }
55 }
56}
57
58/// Accessor for Savings endpoints.
59pub struct Savings<'a, T> {
60 client: &'a OkxClient<T>,
61}
62
63impl<T: Transport> Savings<'_, T> {
64 /// Retrieve savings balances.
65 ///
66 /// `GET /api/v5/finance/savings/balance`. Authenticated.
67 ///
68 /// # Errors
69 ///
70 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero
71 /// OKX code, or transport/decode errors.
72 pub async fn get_saving_balance(&self, ccy: Option<&str>) -> Result<Vec<SavingBalance>, Error> {
73 let query = optional_ccy(ccy);
74 self.client.get(SAVINGS_BALANCE, &query, true).await
75 }
76
77 /// Purchase or redeem savings.
78 ///
79 /// `POST /api/v5/finance/savings/purchase-redempt`. Authenticated.
80 ///
81 /// # Errors
82 ///
83 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero
84 /// OKX code, or transport/decode errors.
85 pub async fn purchase_redemption(
86 &self,
87 request: &SavingsPurchaseRedemptionRequest,
88 ) -> Result<Vec<SavingsPurchaseRedemptionResult>, Error> {
89 self.client
90 .post(SAVINGS_PURCHASE_REDEMPT, request, true)
91 .await
92 }
93
94 /// Set the savings lending rate.
95 ///
96 /// `POST /api/v5/finance/savings/set-lending-rate`. Authenticated.
97 ///
98 /// # Errors
99 ///
100 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero
101 /// OKX code, or transport/decode errors.
102 pub async fn set_lending_rate(
103 &self,
104 ccy: &str,
105 rate: &str,
106 ) -> Result<Vec<SetLendingRateResult>, Error> {
107 let body = SetLendingRateBody { ccy, rate };
108 self.client
109 .post(SAVINGS_SET_LENDING_RATE, &body, true)
110 .await
111 }
112
113 /// Retrieve lending history.
114 ///
115 /// `GET /api/v5/finance/savings/lending-history`. Authenticated.
116 ///
117 /// # Errors
118 ///
119 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero
120 /// OKX code, or transport/decode errors.
121 pub async fn get_lending_history(
122 &self,
123 request: &FinanceHistoryRequest,
124 ) -> Result<Vec<LendingHistory>, Error> {
125 self.client
126 .get(SAVINGS_LENDING_HISTORY, request, true)
127 .await
128 }
129
130 /// Retrieve public borrow history.
131 ///
132 /// `GET /api/v5/finance/savings/lending-rate-history`. Public.
133 ///
134 /// # Errors
135 ///
136 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
137 pub async fn get_public_borrow_history(
138 &self,
139 request: &FinanceHistoryRequest,
140 ) -> Result<Vec<PublicBorrowHistory>, Error> {
141 self.client
142 .get(SAVINGS_PUBLIC_BORROW_HISTORY, request, false)
143 .await
144 }
145
146 /// Retrieve public borrow info.
147 ///
148 /// `GET /api/v5/finance/savings/lending-rate-summary`. Public.
149 ///
150 /// # Errors
151 ///
152 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
153 pub async fn get_public_borrow_info(
154 &self,
155 ccy: Option<&str>,
156 ) -> Result<Vec<PublicBorrowInfo>, Error> {
157 let query = optional_ccy(ccy);
158 self.client
159 .get(SAVINGS_PUBLIC_BORROW_INFO, &query, false)
160 .await
161 }
162}
163
164/// Accessor for Staking/DeFi endpoints.
165pub struct StakingDefi<'a, T> {
166 client: &'a OkxClient<T>,
167}
168
169impl<T: Transport> StakingDefi<'_, T> {
170 /// Retrieve Staking/DeFi offers.
171 ///
172 /// `GET /api/v5/finance/staking-defi/offers`. Authenticated.
173 ///
174 /// # Errors
175 ///
176 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
177 pub async fn get_offers(
178 &self,
179 request: &StakingDefiOffersRequest,
180 ) -> Result<Vec<StakingDefiOffer>, Error> {
181 self.client.get(STAKING_DEFI_OFFERS, request, true).await
182 }
183
184 /// Purchase a Staking/DeFi product.
185 ///
186 /// `POST /api/v5/finance/staking-defi/purchase`. Authenticated.
187 ///
188 /// # Errors
189 ///
190 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
191 pub async fn purchase(
192 &self,
193 request: &StakingDefiPurchaseRequest,
194 ) -> Result<Vec<StakingDefiOrder>, Error> {
195 self.client.post(STAKING_DEFI_PURCHASE, request, true).await
196 }
197
198 /// Redeem a Staking/DeFi order.
199 ///
200 /// `POST /api/v5/finance/staking-defi/redeem`. Authenticated.
201 ///
202 /// # Errors
203 ///
204 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
205 pub async fn redeem(
206 &self,
207 request: &StakingDefiRedeemRequest,
208 ) -> Result<Vec<StakingDefiOrder>, Error> {
209 self.client.post(STAKING_DEFI_REDEEM, request, true).await
210 }
211
212 /// Cancel a Staking/DeFi order.
213 ///
214 /// `POST /api/v5/finance/staking-defi/cancel`. Authenticated.
215 ///
216 /// # Errors
217 ///
218 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
219 pub async fn cancel(
220 &self,
221 request: &StakingDefiCancelRequest,
222 ) -> Result<Vec<StakingDefiOrder>, Error> {
223 self.client.post(STAKING_DEFI_CANCEL, request, true).await
224 }
225
226 /// Retrieve active Staking/DeFi orders.
227 ///
228 /// `GET /api/v5/finance/staking-defi/orders-active`. Authenticated.
229 ///
230 /// # Errors
231 ///
232 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
233 pub async fn get_active_orders(
234 &self,
235 request: &StakingDefiActiveOrdersRequest,
236 ) -> Result<Vec<StakingDefiOrder>, Error> {
237 self.client
238 .get(STAKING_DEFI_ACTIVE_ORDERS, request, true)
239 .await
240 }
241
242 /// Retrieve Staking/DeFi order history.
243 ///
244 /// `GET /api/v5/finance/staking-defi/orders-history`. Authenticated.
245 ///
246 /// # Errors
247 ///
248 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
249 pub async fn get_orders_history(
250 &self,
251 request: &StakingDefiOrderHistoryRequest,
252 ) -> Result<Vec<StakingDefiOrder>, Error> {
253 self.client
254 .get(STAKING_DEFI_ORDERS_HISTORY, request, true)
255 .await
256 }
257}
258
259/// Accessor for ETH staking endpoints.
260pub struct EthStaking<'a, T> {
261 client: &'a OkxClient<T>,
262}
263
264impl<T: Transport> EthStaking<'_, T> {
265 /// Retrieve ETH staking product info.
266 ///
267 /// `GET /api/v5/finance/staking-defi/eth/product-info`. Authenticated.
268 ///
269 /// # Errors
270 ///
271 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
272 pub async fn product_info(&self) -> Result<Vec<StakingProductInfo>, Error> {
273 self.client.get(ETH_PRODUCT_INFO, &NoParams {}, true).await
274 }
275
276 /// Purchase ETH staking.
277 ///
278 /// `POST /api/v5/finance/staking-defi/eth/purchase`. Authenticated.
279 ///
280 /// # Errors
281 ///
282 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
283 pub async fn purchase(&self, amt: &str) -> Result<Vec<StakingOrder>, Error> {
284 let body = AmountBody { amt };
285 self.client.post(ETH_PURCHASE, &body, true).await
286 }
287
288 /// Redeem ETH staking.
289 ///
290 /// `POST /api/v5/finance/staking-defi/eth/redeem`. Authenticated.
291 ///
292 /// # Errors
293 ///
294 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
295 pub async fn redeem(&self, amt: &str) -> Result<Vec<StakingOrder>, Error> {
296 let body = AmountBody { amt };
297 self.client.post(ETH_REDEEM, &body, true).await
298 }
299
300 /// Cancel redeem ETH staking.
301 ///
302 /// `POST /api/v5/finance/staking-defi/eth/cancel-redeem`. Authenticated.
303 ///
304 /// # Errors
305 ///
306 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
307 pub async fn cancel_redeem(&self, ord_id: &str) -> Result<Vec<CancelRedeem>, Error> {
308 let body = CancelRedeemBody { ord_id };
309 self.client.post(ETH_CANCEL_REDEEM, &body, true).await
310 }
311
312 /// Retrieve ETH staking balance.
313 ///
314 /// `GET /api/v5/finance/staking-defi/eth/balance`. Authenticated.
315 ///
316 /// # Errors
317 ///
318 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
319 pub async fn balance(&self) -> Result<Vec<StakingBalance>, Error> {
320 self.client.get(ETH_BALANCE, &NoParams {}, true).await
321 }
322
323 /// Retrieve ETH staking purchase/redeem history.
324 ///
325 /// `GET /api/v5/finance/staking-defi/eth/purchase-redeem-history`. Authenticated.
326 ///
327 /// # Errors
328 ///
329 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
330 pub async fn purchase_redeem_history(
331 &self,
332 request: &FinanceHistoryRequest,
333 ) -> Result<Vec<StakingHistory>, Error> {
334 self.client.get(ETH_HISTORY, request, true).await
335 }
336
337 /// Retrieve ETH staking APY history.
338 ///
339 /// `GET /api/v5/finance/staking-defi/eth/apy-history`. Public.
340 ///
341 /// # Errors
342 ///
343 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
344 pub async fn apy_history(&self, days: &str) -> Result<Vec<StakingApyHistory>, Error> {
345 let query = DaysQuery { days };
346 self.client.get(ETH_APY_HISTORY, &query, false).await
347 }
348}
349
350/// Accessor for SOL staking endpoints.
351pub struct SolStaking<'a, T> {
352 client: &'a OkxClient<T>,
353}
354
355impl<T: Transport> SolStaking<'_, T> {
356 /// Retrieve SOL staking product info.
357 ///
358 /// `GET /api/v5/finance/staking-defi/sol/product-info`. Authenticated.
359 ///
360 /// # Errors
361 ///
362 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
363 pub async fn product_info(&self) -> Result<StakingProductInfo, Error> {
364 self.client.get(SOL_PRODUCT_INFO, &NoParams {}, true).await
365 }
366
367 /// Purchase SOL staking.
368 ///
369 /// `POST /api/v5/finance/staking-defi/sol/purchase`. Authenticated.
370 ///
371 /// # Errors
372 ///
373 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
374 pub async fn purchase(&self, amt: &str) -> Result<Vec<StakingOrder>, Error> {
375 let body = AmountBody { amt };
376 self.client.post(SOL_PURCHASE, &body, true).await
377 }
378
379 /// Redeem SOL staking.
380 ///
381 /// `POST /api/v5/finance/staking-defi/sol/redeem`. Authenticated.
382 ///
383 /// # Errors
384 ///
385 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
386 pub async fn redeem(&self, amt: &str) -> Result<Vec<StakingOrder>, Error> {
387 let body = AmountBody { amt };
388 self.client.post(SOL_REDEEM, &body, true).await
389 }
390
391 /// Retrieve SOL staking balance.
392 ///
393 /// `GET /api/v5/finance/staking-defi/sol/balance`. Authenticated.
394 ///
395 /// # Errors
396 ///
397 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
398 pub async fn balance(&self) -> Result<Vec<StakingBalance>, Error> {
399 self.client.get(SOL_BALANCE, &NoParams {}, true).await
400 }
401
402 /// Retrieve SOL staking purchase/redeem history.
403 ///
404 /// `GET /api/v5/finance/staking-defi/sol/purchase-redeem-history`. Authenticated.
405 ///
406 /// # Errors
407 ///
408 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
409 pub async fn purchase_redeem_history(
410 &self,
411 request: &FinanceHistoryRequest,
412 ) -> Result<Vec<StakingHistory>, Error> {
413 self.client.get(SOL_HISTORY, request, true).await
414 }
415
416 /// Retrieve SOL staking APY history.
417 ///
418 /// `GET /api/v5/finance/staking-defi/sol/apy-history`. Public.
419 ///
420 /// # Errors
421 ///
422 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
423 pub async fn apy_history(&self, days: &str) -> Result<Vec<StakingApyHistory>, Error> {
424 let query = DaysQuery { days };
425 self.client.get(SOL_APY_HISTORY, &query, false).await
426 }
427}
428
429/// Accessor for Flexible Loan endpoints.
430pub struct FlexibleLoan<'a, T> {
431 client: &'a OkxClient<T>,
432}
433
434impl<T: Transport> FlexibleLoan<'_, T> {
435 /// Retrieve borrowable currencies.
436 ///
437 /// `GET /api/v5/finance/flexible-loan/borrow-currencies`. Authenticated.
438 ///
439 /// # Errors
440 ///
441 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
442 pub async fn borrow_currencies(&self) -> Result<Vec<FlexibleLoanCurrency>, Error> {
443 self.client
444 .get(FLEX_BORROW_CURRENCIES, &NoParams {}, true)
445 .await
446 }
447
448 /// Retrieve collateral assets.
449 ///
450 /// `GET /api/v5/finance/flexible-loan/collateral-assets`. Public.
451 ///
452 /// # Errors
453 ///
454 /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
455 pub async fn collateral_assets(
456 &self,
457 request: &FlexibleLoanCollateralAssetsRequest,
458 ) -> Result<Vec<FlexibleLoanCollateralAsset>, Error> {
459 self.client
460 .get(FLEX_COLLATERAL_ASSETS, request, false)
461 .await
462 }
463
464 /// Estimate maximum flexible-loan amount.
465 ///
466 /// `POST /api/v5/finance/flexible-loan/max-loan`. Authenticated.
467 ///
468 /// # Errors
469 ///
470 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
471 pub async fn max_loan(
472 &self,
473 request: &FlexibleLoanMaxLoanRequest,
474 ) -> Result<Vec<FlexibleLoanMaxLoan>, Error> {
475 self.client.post(FLEX_MAX_LOAN, request, true).await
476 }
477
478 /// Retrieve maximum collateral redeem amount.
479 ///
480 /// `GET /api/v5/finance/flexible-loan/max-collateral-redeem-amount`. Authenticated.
481 ///
482 /// # Errors
483 ///
484 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
485 pub async fn max_collateral_redeem_amount(
486 &self,
487 request: &FlexibleLoanMaxRedeemRequest,
488 ) -> Result<Vec<FlexibleLoanMaxRedeem>, Error> {
489 self.client.get(FLEX_MAX_REDEEM, request, true).await
490 }
491
492 /// Adjust flexible-loan collateral.
493 ///
494 /// `POST /api/v5/finance/flexible-loan/adjust-collateral`. Authenticated.
495 ///
496 /// # Errors
497 ///
498 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
499 pub async fn adjust_collateral(
500 &self,
501 request: &FlexibleLoanAdjustCollateralRequest,
502 ) -> Result<Vec<FlexibleLoanOrder>, Error> {
503 self.client
504 .post(FLEX_ADJUST_COLLATERAL, request, true)
505 .await
506 }
507
508 /// Retrieve flexible-loan info.
509 ///
510 /// `GET /api/v5/finance/flexible-loan/loan-info`. Authenticated.
511 ///
512 /// # Errors
513 ///
514 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
515 pub async fn loan_info(
516 &self,
517 request: &FlexibleLoanInfoRequest,
518 ) -> Result<Vec<FlexibleLoanInfo>, Error> {
519 self.client.get(FLEX_LOAN_INFO, request, true).await
520 }
521
522 /// Retrieve flexible-loan history.
523 ///
524 /// `GET /api/v5/finance/flexible-loan/loan-history`. Authenticated.
525 ///
526 /// # Errors
527 ///
528 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
529 pub async fn loan_history(
530 &self,
531 request: &FlexibleLoanHistoryRequest,
532 ) -> Result<Vec<FlexibleLoanHistory>, Error> {
533 self.client.get(FLEX_LOAN_HISTORY, request, true).await
534 }
535
536 /// Retrieve flexible-loan accrued interest.
537 ///
538 /// `GET /api/v5/finance/flexible-loan/interest-accrued`. Authenticated.
539 ///
540 /// # Errors
541 ///
542 /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
543 pub async fn interest_accrued(
544 &self,
545 request: &FlexibleLoanInterestAccruedRequest,
546 ) -> Result<Vec<FlexibleLoanInterest>, Error> {
547 self.client.get(FLEX_INTEREST_ACCRUED, request, true).await
548 }
549}