Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions rust/src/trading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use bullet_exchange_interface::types::{MarketId, OrderType, Side};

use crate::generated::types::SubmitTxResponse;
use crate::types::{CallMessage, UserAction};
use crate::{Client, SDKError, SDKResult, Transaction};
use crate::{Client, SDKError, SDKResult};

// ── Order construction helpers ──────────────────────────────────────────────

Expand Down Expand Up @@ -127,8 +127,7 @@ impl Client {
replace,
sub_account_index,
});
let signed = Transaction::builder().call_message(call_msg).client(self).build()?;
self.send_transaction(&signed).await
self.send_call_message(call_msg).await
}

/// Cancel specific orders on a market. Signs and submits the transaction.
Expand Down Expand Up @@ -157,8 +156,7 @@ impl Client {
) -> SDKResult<SubmitTxResponse> {
let call_msg =
CallMessage::User(UserAction::CancelOrders { market_id, orders, sub_account_index });
let signed = Transaction::builder().call_message(call_msg).client(self).build()?;
self.send_transaction(&signed).await
self.send_call_message(call_msg).await
}

/// Cancel all orders on a specific market. Signs and submits the transaction.
Expand All @@ -175,8 +173,7 @@ impl Client {
) -> SDKResult<SubmitTxResponse> {
let call_msg =
CallMessage::User(UserAction::CancelMarketOrders { market_id, sub_account_index });
let signed = Transaction::builder().call_message(call_msg).client(self).build()?;
self.send_transaction(&signed).await
self.send_call_message(call_msg).await
}

/// Cancel all orders across all markets. Signs and submits the transaction.
Expand All @@ -191,8 +188,7 @@ impl Client {
sub_account_index: Option<u8>,
) -> SDKResult<SubmitTxResponse> {
let call_msg = CallMessage::User(UserAction::CancelAllOrders { sub_account_index });
let signed = Transaction::builder().call_message(call_msg).client(self).build()?;
self.send_transaction(&signed).await
self.send_call_message(call_msg).await
}

// ── Account query convenience methods ─────────────────────────────────
Expand Down Expand Up @@ -292,8 +288,7 @@ impl Client {
) -> SDKResult<SubmitTxResponse> {
let call_msg =
CallMessage::User(UserAction::AmendOrders { market_id, orders, sub_account_index });
let signed = Transaction::builder().call_message(call_msg).client(self).build()?;
self.send_transaction(&signed).await
self.send_call_message(call_msg).await
}
}

Expand Down
29 changes: 29 additions & 0 deletions rust/src/transaction_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,35 @@ impl Client {
Err(self.submit_tx_api_error(error).await?)
}

/// Build, sign, and submit a call message, retrying once if the chain hash
/// changed since startup (401 invalid signature → schema refresh → re-sign).
///
/// Unlike calling `send_transaction` directly, this never returns
/// `TransactionOutdated` — the retry is handled internally, and if the
/// refreshed hash also fails the error is returned as `ApiError`.
pub async fn send_call_message(
&self,
call_message: CallMessage,
) -> SDKResult<SubmitTxResponse> {
let signed =
Transaction::builder().call_message(call_message.clone()).client(self).build()?;
match self.send_transaction(&signed).await {
Err(SDKError::TransactionOutdated) => {
// chain hash was refreshed; re-sign with the new hash and retry once.
// submit directly so a second 401 comes back as ApiError, not TransactionOutdated
let signed =
Transaction::builder().call_message(call_message).client(self).build()?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this automaticaly fetch the new schema/hash?

let body = Transaction::to_base64(&signed)?;
match self.client().submit_tx(&SubmitTxRequest { body }).await {
Ok(r) => Ok(r.into_inner()),
Err(ErrorResponse(r)) => Err(SDKError::ApiError(r.into_inner())),
Err(e) => Err(e.into()),
}
}
other => other,
}
}

async fn submit_tx_api_error(&self, error: ApiErrorResponse) -> SDKResult<SDKError> {
if error.status == 401 && error.message.contains("Invalid signature") {
self.update_schema().await?;
Expand Down
4 changes: 1 addition & 3 deletions wasm/src/transaction_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,9 +480,7 @@ impl WasmTradingApi {
&self,
msg: WasmCallMessage,
) -> WasmResult<crate::generated::WasmSubmitTxResponse> {
let signed =
RustTransaction::builder().call_message(msg.inner).client(&self.inner).build()?;
let resp = self.inner.send_transaction(&signed).await?;
let resp = self.inner.send_call_message(msg.inner).await?;
Ok(crate::generated::WasmSubmitTxResponse(resp))
}
}