renegade_sdk/renegade_wallet_client/actions/
withdraw.rs1use std::time::Duration;
4
5use alloy::primitives::Address;
6use renegade_circuit_types::Amount;
7use renegade_crypto::fields::scalar_to_u256;
8use renegade_darkpool_types::balance::DarkpoolStateBalance;
9use renegade_external_api::http::balance::{
10 WITHDRAW_BALANCE_ROUTE, WithdrawBalanceRequest, WithdrawBalanceResponse,
11};
12use renegade_solidity_abi::v2::{
13 IDarkpoolV2::WithdrawalAuth, transfer_auth::withdrawal::create_withdrawal_auth,
14};
15
16use crate::{
17 RenegadeClientError,
18 actions::{NON_BLOCKING_PARAM, construct_http_path},
19 client::RenegadeClient,
20 websocket::TaskWaiter,
21};
22
23const TASK_WAITER_TIMEOUT: Duration = Duration::from_secs(120);
28
29impl RenegadeClient {
31 pub async fn withdraw(&self, mint: Address, amount: Amount) -> Result<(), RenegadeClientError> {
34 let request = self.build_withdrawal_request(mint, amount).await?;
35
36 let path = self.build_withdrawal_request_path(mint, false)?;
37
38 self.relayer_client.post::<_, WithdrawBalanceResponse>(&path, request).await?;
39
40 Ok(())
41 }
42
43 pub async fn enqueue_withdrawal(
46 &self,
47 mint: Address,
48 amount: Amount,
49 ) -> Result<TaskWaiter, RenegadeClientError> {
50 let request = self.build_withdrawal_request(mint, amount).await?;
51
52 let path = self.build_withdrawal_request_path(mint, true)?;
53
54 let WithdrawBalanceResponse { task_id, .. } =
55 self.relayer_client.post(&path, request).await?;
56
57 let task_waiter = self.watch_task(task_id, TASK_WAITER_TIMEOUT).await?;
58
59 Ok(task_waiter)
60 }
61}
62
63impl RenegadeClient {
65 async fn build_withdrawal_request(
67 &self,
68 mint: Address,
69 amount: Amount,
70 ) -> Result<WithdrawBalanceRequest, RenegadeClientError> {
71 let signature = self.build_withdrawal_auth(mint, amount).await?;
72 Ok(WithdrawBalanceRequest { amount, signature })
73 }
74
75 async fn build_withdrawal_auth(
78 &self,
79 mint: Address,
80 amount: Amount,
81 ) -> Result<Vec<u8>, RenegadeClientError> {
82 let balance = self.get_balance_by_mint(mint).await?;
83 let mut state_balance: DarkpoolStateBalance =
84 crate::renegade_wallet_client::conversions::api_balance_to_state_balance(balance)?;
85
86 simulate_fee_payments(&mut state_balance);
92
93 state_balance.inner.amount -= amount;
96 let new_amount = state_balance.inner.amount;
97 let new_amount_public_share = state_balance.stream_cipher_encrypt(&new_amount);
98 state_balance.public_share.amount = new_amount_public_share;
99 state_balance.compute_recovery_id();
100
101 let commitment = scalar_to_u256(&state_balance.compute_commitment());
104 let chain_id = self.get_chain_id();
105
106 let WithdrawalAuth { signature } =
107 create_withdrawal_auth(commitment, chain_id, self.get_account_signer())
108 .map_err(RenegadeClientError::signing)?;
109
110 Ok(signature.to_vec())
111 }
112
113 fn build_withdrawal_request_path(
115 &self,
116 mint: Address,
117 non_blocking: bool,
118 ) -> Result<String, RenegadeClientError> {
119 let path = construct_http_path!(WITHDRAW_BALANCE_ROUTE, "account_id" => self.get_account_id(), "mint" => mint);
120 let query_string =
121 serde_urlencoded::to_string(&[(NON_BLOCKING_PARAM, non_blocking.to_string())])
122 .map_err(RenegadeClientError::serde)?;
123
124 Ok(format!("{path}?{query_string}"))
125 }
126}
127
128fn simulate_fee_payments(state_balance: &mut DarkpoolStateBalance) {
136 if state_balance.inner.relayer_fee_balance > 0 {
138 state_balance.pay_relayer_fee();
139 state_balance.reencrypt_relayer_fee();
140 state_balance.compute_recovery_id();
141 }
142
143 if state_balance.inner.protocol_fee_balance > 0 {
147 state_balance.pay_protocol_fee(Address::ZERO);
148 state_balance.reencrypt_protocol_fee();
149 state_balance.compute_recovery_id();
150 }
151}