use std::sync::Arc;
use solana_keypair::Keypair;
use super::super::format::truncate_balance;
use super::super::i18n::strings;
use super::super::state::TxStatusMsg;
use super::compute_budget::build_compute_budget_ixs_raw;
use super::confirmation::{compile_and_sign, subscribe_send_confirm, ConfirmError};
use super::context::TxContext;
use super::error::{
format_not_confirmed_error, log_tx_error, not_confirmed_is_onchain_execution_failure,
parse_phoenix_tx_error,
};
pub fn submit_funds_transfer(
keypair: Arc<Keypair>,
ctx: Arc<TxContext>,
amount: f64,
is_deposit: bool,
tx_status: tokio::sync::mpsc::UnboundedSender<TxStatusMsg>,
) {
tokio::spawn(async move {
use phoenix_rise::PhoenixTxBuilder;
let s = strings();
let amount = truncate_balance(amount);
let flow = if is_deposit {
s.tx_flow_deposit
} else {
s.tx_flow_withdraw
};
let fund_scope = format!("{:.2} USDC {}", amount, flow);
let builder = PhoenixTxBuilder::new(&ctx.metadata);
let ixs = if is_deposit {
match builder.build_deposit_funds(ctx.authority_v2, ctx.trader_pda_v2, amount) {
Ok(instructions) => instructions,
Err(e) => {
let _ = tx_status.send(TxStatusMsg::SetStatus {
title: format!("{} — {}", s.tx_failed_build_deposit, fund_scope),
detail: format!("{}", e),
});
return;
}
}
} else {
match builder.build_withdraw_funds(ctx.authority_v2, ctx.trader_pda_v2, amount) {
Ok(instructions) => instructions,
Err(e) => {
let _ = tx_status.send(TxStatusMsg::SetStatus {
title: format!("{} — {}", s.tx_failed_build_withdrawal, fund_scope),
detail: format!("{}", e),
});
return;
}
}
};
let mut mapped_ixs = ixs;
mapped_ixs.extend(build_compute_budget_ixs_raw(100_000));
let _ = tx_status.send(TxStatusMsg::SetStatus {
title: format!("{} {}…", s.tx_broadcasting, fund_scope),
detail: String::new(),
});
let (tx, sig) = match compile_and_sign(&ctx, &keypair, &mapped_ixs).await {
Ok(pair) => pair,
Err(e) => {
let _ = tx_status.send(TxStatusMsg::SetStatus {
title: format!("{} — {}", s.tx_failed_prepare, fund_scope),
detail: e,
});
return;
}
};
let sig_str = sig.to_string();
let _ = tx_status.send(TxStatusMsg::SetStatus {
title: format!("{} — {}…", s.tx_awaiting_confirm, fund_scope),
detail: sig_str.clone(),
});
match subscribe_send_confirm(&ctx, &tx, &sig).await {
Ok(()) => {
let confirmed_prefix = if is_deposit {
s.tx_deposit_confirmed
} else {
s.tx_withdrawal_confirmed
};
let _ = tx_status.send(TxStatusMsg::SetStatus {
title: format!("{} {:.2} {}", confirmed_prefix, amount, s.tx_usdc_confirmed),
detail: sig_str,
});
}
Err(ConfirmError::Rejected(e)) => {
log_tx_error(
None,
&format!("funds transfer rejected — {}", fund_scope),
&e,
);
let _ = tx_status.send(TxStatusMsg::SetStatus {
title: format!("{} — {}", s.tx_tx_rejected, fund_scope),
detail: parse_phoenix_tx_error(&e),
});
}
Err(ConfirmError::NotConfirmed(e)) => {
log_tx_error(
Some(&sig_str),
&format!("funds transfer not confirmed — {}", fund_scope),
&e,
);
let onchain_fail = not_confirmed_is_onchain_execution_failure(&e);
let mapped = format_not_confirmed_error(&e);
let (title, detail) = if onchain_fail {
(
format!("{} — {}", s.tx_transfer_failed, fund_scope),
parse_phoenix_tx_error(&e),
)
} else {
(
format!(
"{} — {} ({})",
s.tx_transfer_not_confirmed, fund_scope, mapped
),
sig_str,
)
};
let _ = tx_status.send(TxStatusMsg::SetStatus { title, detail });
}
}
});
}