use rust_decimal::{Decimal, serde::str_option::deserialize as option_decimal};
use serde::{Deserialize, Serialize};
use serde_aux::prelude::{
deserialize_number_from_string as number,
deserialize_option_number_from_string as option_number,
};
use crate::{
AccountType, DepositStatus, Side, Timestamp, TransferStatus, WithdrawStatus, enums::Category,
serde::empty_string_as_none,
};
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct InternalTransferRequest {
pub transfer_id: String,
pub coin: String,
pub amount: Decimal,
pub from_account_type: AccountType,
pub to_account_type: AccountType,
}
impl InternalTransferRequest {
pub fn new(
transfer_id: impl Into<String>,
coin: impl Into<String>,
amount: Decimal,
from_account_type: AccountType,
to_account_type: AccountType,
) -> Self {
let transfer_id: String = transfer_id.into();
let coin: String = coin.into();
Self {
transfer_id,
coin,
amount,
from_account_type,
to_account_type,
}
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct TransferResult {
pub transfer_id: String,
pub status: TransferStatus,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetInternalTransferRecordsParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub transfer_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<TransferStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetInternalTransferRecordsParams {
pub fn new() -> Self {
Self {
transfer_id: None,
coin: None,
status: None,
start_time: None,
end_time: None,
limit: None,
cursor: None,
}
}
pub fn with_transfer_id(mut self, v: impl Into<String>) -> Self {
self.transfer_id = Some(v.into());
self
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
pub fn with_status(mut self, v: TransferStatus) -> Self {
self.status = Some(v);
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
impl Default for GetInternalTransferRecordsParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct InternalTransferEntry {
pub transfer_id: String,
pub coin: String,
pub amount: Decimal,
pub from_account_type: AccountType,
pub to_account_type: AccountType,
#[serde(deserialize_with = "number")]
pub timestamp: Timestamp,
pub status: TransferStatus,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct UniversalTransferRequest {
pub transfer_id: String,
pub coin: String,
pub amount: Decimal,
pub from_member_id: i64,
pub to_member_id: i64,
pub from_account_type: AccountType,
pub to_account_type: AccountType,
}
impl UniversalTransferRequest {
pub fn new(
transfer_id: impl Into<String>,
coin: impl Into<String>,
amount: Decimal,
from_member_id: i64,
to_member_id: i64,
from_account_type: AccountType,
to_account_type: AccountType,
) -> Self {
let transfer_id: String = transfer_id.into();
let coin: String = coin.into();
Self {
transfer_id,
coin,
amount,
from_member_id,
to_member_id,
from_account_type,
to_account_type,
}
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetUniversalTransferRecordsParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub transfer_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<TransferStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetUniversalTransferRecordsParams {
pub fn new() -> Self {
Self {
transfer_id: None,
coin: None,
status: None,
start_time: None,
end_time: None,
limit: None,
cursor: None,
}
}
pub fn with_transfer_id(mut self, v: impl Into<String>) -> Self {
self.transfer_id = Some(v.into());
self
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
pub fn with_status(mut self, v: TransferStatus) -> Self {
self.status = Some(v);
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
impl Default for GetUniversalTransferRecordsParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct UniversalTransferEntry {
pub transfer_id: String,
pub coin: String,
pub amount: Decimal,
pub from_member_id: String,
pub to_member_id: String,
pub from_account_type: AccountType,
pub to_account_type: AccountType,
#[serde(deserialize_with = "number")]
pub timestamp: Timestamp,
pub status: TransferStatus,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetTransferableCoinsParams {
pub from_account_type: AccountType,
pub to_account_type: AccountType,
}
impl GetTransferableCoinsParams {
pub fn new(from_account_type: AccountType, to_account_type: AccountType) -> Self {
Self {
from_account_type,
to_account_type,
}
}
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SaveTransferSubMemberRequest {
pub sub_member_ids: String,
}
impl SaveTransferSubMemberRequest {
pub fn new(sub_member_ids: impl Into<String>) -> Self {
let sub_member_ids: String = sub_member_ids.into();
Self { sub_member_ids }
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct TransferableSubMembers {
pub sub_member_ids: Vec<String>,
pub transferable_sub_member_ids: Vec<String>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetAccountCoinBalanceParams {
pub account_type: AccountType,
pub coin: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub member_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_member_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_account_type: Option<AccountType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub with_bonus: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub with_transfer_safe_amount: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub with_ltv_transfer_safe_amount: Option<i64>,
}
impl GetAccountCoinBalanceParams {
pub fn new(account_type: AccountType, coin: impl Into<String>) -> Self {
let coin: String = coin.into();
Self {
account_type,
coin,
member_id: None,
to_member_id: None,
to_account_type: None,
with_bonus: None,
with_transfer_safe_amount: None,
with_ltv_transfer_safe_amount: None,
}
}
pub fn with_member_id(mut self, v: impl Into<String>) -> Self {
self.member_id = Some(v.into());
self
}
pub fn with_to_member_id(mut self, v: impl Into<String>) -> Self {
self.to_member_id = Some(v.into());
self
}
pub fn with_to_account_type(mut self, v: AccountType) -> Self {
self.to_account_type = Some(v);
self
}
pub fn with_bonus(mut self, v: i64) -> Self {
self.with_bonus = Some(v);
self
}
pub fn with_transfer_safe_amount(mut self, v: i64) -> Self {
self.with_transfer_safe_amount = Some(v);
self
}
pub fn with_ltv_transfer_safe_amount(mut self, v: i64) -> Self {
self.with_ltv_transfer_safe_amount = Some(v);
self
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AccountCoinBalance {
pub account_type: AccountType,
pub biz_type: i64,
pub account_id: String,
pub member_id: String,
pub balance: CoinBalance,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CoinBalance {
pub coin: String,
pub wallet_balance: Decimal,
pub transfer_balance: Decimal,
pub bonus: Decimal,
#[serde(default, deserialize_with = "option_decimal")]
pub transfer_safe_amount: Option<Decimal>,
#[serde(default, deserialize_with = "option_decimal")]
pub ltv_transfer_safe_amount: Option<Decimal>,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetAssetInfoParams {
pub account_type: AccountType,
#[serde(skip_serializing_if = "Option::is_none")]
pub coin: Option<String>,
}
impl GetAssetInfoParams {
pub fn new(account_type: AccountType) -> Self {
Self {
account_type,
coin: None,
}
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AssetInfoResult {
pub spot: SpotAssetInfo,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SpotAssetInfo {
pub status: String,
pub assets: Vec<SpotAsset>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SpotAsset {
pub coin: String,
pub frozen: Decimal,
pub free: Decimal,
pub withdraw: Decimal,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetDepositAllowedCoinInfoParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub chain: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetDepositAllowedCoinInfoParams {
pub fn new() -> Self {
Self {
coin: None,
chain: None,
limit: None,
cursor: None,
}
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
pub fn with_chain(mut self, v: impl Into<String>) -> Self {
self.chain = Some(v.into());
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
impl Default for GetDepositAllowedCoinInfoParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DepositAllowedCoinInfoResult {
pub config_list: Vec<DepositCoinConfig>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub next_page_cursor: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DepositCoinConfig {
pub coin: String,
pub chain: String,
pub coin_show_name: String,
pub chain_type: String,
#[serde(deserialize_with = "number")]
pub block_confirm_number: u32,
pub min_deposit_amount: Decimal,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetDepositRecordsParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tx_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetDepositRecordsParams {
pub fn new() -> Self {
Self {
id: None,
tx_id: None,
coin: None,
start_time: None,
end_time: None,
limit: None,
cursor: None,
}
}
pub fn with_id(mut self, v: impl Into<String>) -> Self {
self.id = Some(v.into());
self
}
pub fn with_tx_id(mut self, v: impl Into<String>) -> Self {
self.tx_id = Some(v.into());
self
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
impl Default for GetDepositRecordsParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetSubDepositRecordsParams {
pub sub_member_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tx_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetSubDepositRecordsParams {
pub fn new(sub_member_id: impl Into<String>) -> Self {
let sub_member_id: String = sub_member_id.into();
Self {
sub_member_id,
id: None,
tx_id: None,
coin: None,
start_time: None,
end_time: None,
limit: None,
cursor: None,
}
}
pub fn with_id(mut self, v: impl Into<String>) -> Self {
self.id = Some(v.into());
self
}
pub fn with_tx_id(mut self, v: impl Into<String>) -> Self {
self.tx_id = Some(v.into());
self
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DepositRecords {
pub rows: Vec<DepositRecord>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub next_page_cursor: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DepositRecord {
pub id: String,
pub coin: String,
pub chain: String,
pub amount: Decimal,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub tx_id: Option<String>,
pub status: DepositStatus,
pub to_address: String,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub tag: Option<String>,
pub deposit_fee: Decimal,
#[serde(deserialize_with = "option_number")]
pub success_at: Option<Timestamp>,
pub confirmations: String,
pub tx_index: String,
pub block_hash: String,
pub batch_release_limit: String,
pub deposit_type: i64,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub from_address: Option<String>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub tax_deposit_records_id: Option<String>,
#[serde(default)]
pub tax_status: Option<i64>,
#[serde(default)]
pub travel_rule_status: Option<i64>,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetDepositAddressParams {
pub coin: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub chain_type: Option<String>,
}
impl GetDepositAddressParams {
pub fn new(coin: impl Into<String>) -> Self {
let coin: String = coin.into();
Self {
coin,
chain_type: None,
}
}
pub fn with_chain_type(mut self, v: impl Into<String>) -> Self {
self.chain_type = Some(v.into());
self
}
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetSubDepositAddressParams {
pub coin: String,
pub chain_type: String,
pub sub_member_id: String,
}
impl GetSubDepositAddressParams {
pub fn new(
coin: impl Into<String>,
chain_type: impl Into<String>,
sub_member_id: impl Into<String>,
) -> Self {
let coin: String = coin.into();
let chain_type: String = chain_type.into();
let sub_member_id: String = sub_member_id.into();
Self {
coin,
chain_type,
sub_member_id,
}
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DepositAddress {
pub coin: String,
pub chains: Vec<DepositChain>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DepositChain {
pub chain_type: String,
pub address_deposit: String,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub tag_deposit: Option<String>,
pub chain: String,
pub batch_release_limit: String,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub contract_address: Option<String>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetWithdrawalRecordsParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub withdraw_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tx_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub withdraw_type: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetWithdrawalRecordsParams {
pub fn new() -> Self {
Self {
withdraw_id: None,
tx_id: None,
coin: None,
withdraw_type: None,
start_time: None,
end_time: None,
limit: None,
cursor: None,
}
}
pub fn with_withdraw_id(mut self, v: impl Into<String>) -> Self {
self.withdraw_id = Some(v.into());
self
}
pub fn with_tx_id(mut self, v: impl Into<String>) -> Self {
self.tx_id = Some(v.into());
self
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
pub fn with_withdraw_type(mut self, v: i64) -> Self {
self.withdraw_type = Some(v);
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
impl Default for GetWithdrawalRecordsParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct WithdrawRecords {
pub rows: Vec<WithdrawRecord>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub next_page_cursor: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct WithdrawRecord {
#[serde(default, deserialize_with = "empty_string_as_none")]
pub tx_id: Option<String>,
pub coin: String,
pub chain: String,
pub amount: Decimal,
pub withdraw_fee: Decimal,
pub status: WithdrawStatus,
pub to_address: String,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub tag: Option<String>,
#[serde(deserialize_with = "number")]
pub create_time: Timestamp,
#[serde(deserialize_with = "number")]
pub update_time: Timestamp,
pub withdraw_id: String,
pub withdraw_type: i64,
#[serde(default, deserialize_with = "option_decimal")]
pub tax: Option<Decimal>,
#[serde(default, deserialize_with = "option_decimal")]
pub tax_rate: Option<Decimal>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub tax_type: Option<String>,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct WithdrawRequest {
pub coin: String,
pub address: String,
pub amount: Decimal,
pub timestamp: i64,
pub account_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub chain: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub force_chain: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fee_type: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub request_id: Option<String>,
}
impl WithdrawRequest {
pub fn new(
coin: impl Into<String>,
address: impl Into<String>,
amount: Decimal,
timestamp: i64,
account_type: impl Into<String>,
) -> Self {
let coin: String = coin.into();
let address: String = address.into();
let account_type: String = account_type.into();
Self {
coin,
address,
amount,
timestamp,
account_type,
chain: None,
tag: None,
force_chain: None,
fee_type: None,
request_id: None,
}
}
pub fn with_chain(mut self, v: impl Into<String>) -> Self {
self.chain = Some(v.into());
self
}
pub fn with_tag(mut self, v: impl Into<String>) -> Self {
self.tag = Some(v.into());
self
}
pub fn with_force_chain(mut self, v: i64) -> Self {
self.force_chain = Some(v);
self
}
pub fn with_fee_type(mut self, v: i64) -> Self {
self.fee_type = Some(v);
self
}
pub fn with_request_id(mut self, v: impl Into<String>) -> Self {
self.request_id = Some(v.into());
self
}
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct WithdrawResult {
pub id: String,
}
#[derive(Debug, Serialize, Clone)]
pub struct CancelWithdrawalRequest {
pub id: String,
}
impl CancelWithdrawalRequest {
pub fn new(id: impl Into<String>) -> Self {
let id: String = id.into();
Self { id }
}
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct CancelWithdrawalResult {
pub status: i64,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetWithdrawableAmountParams {
pub coin: String,
}
impl GetWithdrawableAmountParams {
pub fn new(coin: impl Into<String>) -> Self {
let coin: String = coin.into();
Self { coin }
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct WithdrawableAmountResult {
pub limit_amount_usd: Decimal,
pub withdrawable_amount: WithdrawableAmountByWallet,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct WithdrawableAmountByWallet {
#[serde(rename = "SPOT")]
pub spot: Option<WithdrawableAmountEntry>,
#[serde(rename = "FUND")]
pub fund: Option<WithdrawableAmountEntry>,
#[serde(rename = "UTA")]
pub uta: Option<WithdrawableAmountEntry>,
#[serde(rename = "EARN")]
pub earn: Option<WithdrawableAmountEntry>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct WithdrawableAmountEntry {
pub coin: String,
pub withdrawable_amount: Decimal,
pub available_balance: Decimal,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetCoinInfoParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub coin: Option<String>,
}
impl GetCoinInfoParams {
pub fn new() -> Self {
Self { coin: None }
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
}
impl Default for GetCoinInfoParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CoinInfoResult {
pub rows: Vec<CoinInfo>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CoinInfo {
pub name: String,
pub coin: String,
pub chains: Vec<CoinChain>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CoinChain {
pub chain: String,
pub chain_type: String,
pub confirmation: String,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub withdraw_fee: Option<Decimal>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub deposit_min: Option<Decimal>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub withdraw_min: Option<Decimal>,
pub min_accuracy: String,
pub chain_deposit: String,
pub chain_withdraw: String,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub withdraw_percentage_fee: Option<Decimal>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub contract_address: Option<String>,
pub safe_confirm_number: String,
pub withdraw_max: String,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetExchangeOrderRecordParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub from_coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetExchangeOrderRecordParams {
pub fn new() -> Self {
Self {
from_coin: None,
to_coin: None,
limit: None,
cursor: None,
}
}
pub fn with_from_coin(mut self, v: impl Into<String>) -> Self {
self.from_coin = Some(v.into());
self
}
pub fn with_to_coin(mut self, v: impl Into<String>) -> Self {
self.to_coin = Some(v.into());
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
impl Default for GetExchangeOrderRecordParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ExchangeOrderRecords {
pub order_body: Vec<ExchangeOrderRecord>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub next_page_cursor: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ExchangeOrderRecord {
pub from_coin: String,
pub from_amount: Decimal,
pub to_coin: String,
pub to_amount: Decimal,
pub exchange_rate: Decimal,
#[serde(deserialize_with = "number")]
pub created_time: Timestamp,
pub exchange_tx_id: String,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetDeliveryRecordParams {
pub category: Category,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exp_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetDeliveryRecordParams {
pub fn new(category: Category) -> Self {
Self {
category,
symbol: None,
start_time: None,
end_time: None,
exp_date: None,
limit: None,
cursor: None,
}
}
pub fn with_symbol(mut self, v: impl Into<String>) -> Self {
self.symbol = Some(v.into());
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_exp_date(mut self, v: impl Into<String>) -> Self {
self.exp_date = Some(v.into());
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DeliveryRecord {
pub delivery_time: Timestamp,
pub symbol: String,
pub side: Side,
pub position: Decimal,
pub entry_price: Decimal,
pub delivery_price: Decimal,
#[serde(default, deserialize_with = "option_decimal")]
pub strike: Option<Decimal>,
pub fee: Decimal,
pub delivery_rpl: Decimal,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetSettlementRecordParams {
pub category: Category,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetSettlementRecordParams {
pub fn new(category: Category) -> Self {
Self {
category,
symbol: None,
start_time: None,
end_time: None,
limit: None,
cursor: None,
}
}
pub fn with_symbol(mut self, v: impl Into<String>) -> Self {
self.symbol = Some(v.into());
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SettlementRecord {
pub symbol: String,
pub side: Side,
pub size: Decimal,
pub session_avg_price: Decimal,
pub mark_price: Decimal,
pub realised_pnl: Decimal,
#[serde(deserialize_with = "number")]
pub created_time: Timestamp,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetCoinGreeksParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub base_coin: Option<String>,
}
impl GetCoinGreeksParams {
pub fn new() -> Self {
Self { base_coin: None }
}
pub fn with_base_coin(mut self, v: impl Into<String>) -> Self {
self.base_coin = Some(v.into());
self
}
}
impl Default for GetCoinGreeksParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CoinGreeks {
pub base_coin: String,
pub total_delta: Decimal,
pub total_gamma: Decimal,
pub total_vega: Decimal,
pub total_theta: Decimal,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn coin_chain_with_empty_limits() {
let json = r#"{"rows":[{"name":"USDT","coin":"USDT","remainAmount":"100","chains":[{
"chainType":"X","confirmation":"","withdrawFee":"","depositMin":"","withdrawMin":"",
"chain":"X","chainDeposit":"0","chainWithdraw":"0","minAccuracy":"8",
"withdrawPercentageFee":"","contractAddress":"","safeConfirmNumber":"","withdrawMax":""
}]}]}"#;
let result: CoinInfoResult = serde_json::from_str(json).unwrap();
let chain = &result.rows[0].chains[0];
assert_eq!(chain.deposit_min, None);
assert_eq!(chain.withdraw_fee, None);
assert_eq!(chain.contract_address, None);
}
#[test]
fn deposit_coin_config_with_numeric_block_confirm_number() {
let json = r#"{"configList":[{"coin":"USDT","chain":"ETH","coinShowName":"USDT",
"chainType":"ERC20","blockConfirmNumber":1,"minDepositAmount":"0.01"}],
"nextPageCursor":""}"#;
let result: DepositAllowedCoinInfoResult = serde_json::from_str(json).unwrap();
assert_eq!(result.config_list[0].block_confirm_number, 1);
}
}