Skip to content
Merged
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
16 changes: 14 additions & 2 deletions crates/solvers/src/infra/dex/bitget/dto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,24 @@ impl SwapTransaction {
/// A Bitget API response wrapper.
///
/// On success `status` is 0 and `data` contains the result.
/// On error `status` is non-zero and `data` is null.
/// On error `status` is 1, `error_code` identifies the failure, and `data` is
/// null.
///
/// See <https://web3.bitget.com/en/docs/swap-order#error-code-list>
#[derive(Deserialize, Clone, Debug)]
pub struct Response<T> {
/// Response status code (0 = success).
/// Response status code (0 = success, 1 = failure).
pub status: i64,

/// Bitget error code (e.g. 80005 for insufficient liquidity).
/// Only present when `status` is non-zero.
#[serde(default)]
pub error_code: Option<i64>,

/// Human-readable error description.
#[serde(default)]
pub message: Option<String>,

/// Response data — `None` when the API returns an error.
pub data: Option<T>,
}
47 changes: 37 additions & 10 deletions crates/solvers/src/infra/dex/bitget/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,31 @@ impl Bitget {
Ok(BASE64_STANDARD.encode(signature))
}

/// Bitget error handling based on status codes.
fn handle_api_error(status: i64, body: String) -> Result<(), Error> {
Err(match status {
0 => return Ok(()),
429 => Error::RateLimited,
404 => Error::NotFound,
_ => Error::Api { status, body },
/// Bitget error handling based on `error_code`.
///
/// See <https://web3.bitget.com/en/docs/swap-order#error-code-list>
fn handle_api_error(
status: i64,
error_code: Option<i64>,
message: String,
) -> Result<(), Error> {
if status == 0 {
return Ok(());
}

Err(match error_code.unwrap_or(80000) {
80001 // Insufficient token balance
| 80004 // Order expired
| 80005 // Insufficient liquidity
| 80008 // Reverse quote did not converge
| 80009 // Token info not found
| 80010 // Price/gas price not found
=> Error::NotFound,
80002 // Amount below minimum
| 80003 // Amount above maximum
| 80006 // Illegal request
=> Error::BadRequest,
code => Error::Api { code, message },
})
}

Expand Down Expand Up @@ -256,14 +274,21 @@ impl Bitget {
let status = response.status();
let body = response.text().await.map_err(util::http::Error::from)?;

if status == reqwest::StatusCode::TOO_MANY_REQUESTS {
return Err(Error::RateLimited);
}
if !status.is_success() {
return Err(util::http::Error::Status(status, body).into());
}

let response: dto::Response<U> =
serde_json::from_str(&body).map_err(util::http::Error::from)?;

Self::handle_api_error(response.status, body)?;
Self::handle_api_error(
response.status,
response.error_code,
response.message.unwrap_or_default(),
)?;
response.data.ok_or(Error::NotFound)
}
}
Expand Down Expand Up @@ -294,8 +319,10 @@ pub enum Error {
AmountConversionFailed,
#[error("decimals are missing for the swapped tokens")]
MissingDecimals,
#[error("api error status {status}: {body}")]
Api { status: i64, body: String },
#[error("bad request")]
BadRequest,
#[error("api error code {code}: {message}")]
Api { code: i64, message: String },
#[error(transparent)]
Http(#[from] util::http::Error),
}
2 changes: 1 addition & 1 deletion crates/solvers/src/infra/dex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ impl From<bitget::Error> for Error {
match err {
bitget::Error::OrderNotSupported => Self::OrderNotSupported,
bitget::Error::NotFound => Self::NotFound,
bitget::Error::MissingDecimals => Self::BadRequest,
bitget::Error::MissingDecimals | bitget::Error::BadRequest => Self::BadRequest,
bitget::Error::RateLimited => Self::RateLimited,
_ => Self::Other(Box::new(err)),
}
Expand Down
8 changes: 5 additions & 3 deletions crates/solvers/src/tests/bitget/not_found.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ use {
#[tokio::test]
async fn sell_no_liquidity() {
let api = mock::http::setup(vec![
// Swap request returns an error status.
// Swap request returns an error status (insufficient liquidity).
mock::http::Expectation::Post {
path: mock::http::Path::exact("bgw-pro/swapx/pro/swap"),
req: mock::http::RequestBody::Any,
res: json!({
"status": 404,
"data": {}
"status": 1,
"error_code": 80005,
"message": "Insufficient liquidity; transaction cannot be completed at this time.",
"data": null
}),
},
])
Expand Down
Loading