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