use serde::Deserialize;
#[cfg(feature = "sign")]
use crate::account::keys::{ApiKey, Wallet, verify};
use crate::client::Network;
use crate::client::http::{ApiError, Call, Transport, read};
#[cfg(feature = "sign")]
use crate::client::{Client, Http, SendError};
use crate::transfer::send::{Memo, Transfer};
use crate::utils::units::BadUnits;
use crate::utils::{AccountIndex, Address, Dec};
#[must_use]
pub const fn minimum_fast_withdrawal(network: Network) -> Dec {
match network {
Network::Lighter => Dec::from_int(4),
Network::Robinhood => Dec::from_int(1),
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct FastWithdrawInfo {
#[serde(rename = "to_account_index")]
pub pool: AccountIndex,
pub withdraw_limit: Dec,
pub max_withdrawal_amount: Dec,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct FastWithdrawn {
#[serde(default)]
pub tx_hash: Option<String>,
}
#[must_use]
pub fn fast_withdraw_info_call(account: AccountIndex) -> Call {
Call::get("fastwithdraw/info").field("account_index", account).authed()
}
pub async fn fast_withdraw_info(
transport: &impl Transport,
account: AccountIndex,
) -> Result<FastWithdrawInfo, ApiError> {
read(transport, fast_withdraw_info_call(account)).await
}
pub fn fast_withdrawal(
network: Network,
pool: AccountIndex,
to: Address,
amount: Dec,
fee: u64,
) -> Result<Transfer, BadUnits> {
Ok(Transfer::collateral(network, pool, amount)?.with_fee(fee).with_memo(Memo::address(to)))
}
#[must_use]
pub fn fast_withdraw_call(tx_info: String, to: Address) -> Call {
Call::post("fastwithdraw").field("tx_info", tx_info).field("to_address", to.to_hex()).authed()
}
#[cfg(feature = "sign")]
pub async fn fast_withdraw<H: Http>(
client: &Client<H, ApiKey>,
owner: &impl Wallet,
to: Address,
amount: Dec,
) -> Result<FastWithdrawn, SendError> {
let account = client.key().account();
let info = fast_withdraw_info(client, account).await?;
let fee = crate::transfer::fees::transfer_fee(client, account, Some(info.pool)).await?;
let transfer = fast_withdrawal(client.network(), info.pool, to, amount, fee)
.map_err(|error| crate::transfer::send::refused_units("Amount", &error))?;
let signed = client.sign(&transfer).await?;
let posted = async {
let message = signed.l1_message().unwrap_or_default();
let signature = owner.sign_message(message).await?;
verify(message, &signature, owner.address())?;
let tx_info = signed.tx_info_with_l1(&signature.to_hex()).unwrap_or_else(|| signed.tx_info());
Ok::<_, SendError>(read::<FastWithdrawn>(client, fast_withdraw_call(tx_info, to)).await?)
}
.await;
if posted.is_err() {
client.forget_nonce();
}
posted
}
#[cfg(test)]
#[path = "tests/fast.rs"]
mod tests;