Skip to content

Commit

Permalink
Merge pull request #9 from fran0x/master
Browse files Browse the repository at this point in the history
docs + websocket + RFQs
  • Loading branch information
tomlinton authored Nov 15, 2024
2 parents a072dff + 30b1648 commit d1a830d
Show file tree
Hide file tree
Showing 33 changed files with 888 additions and 227 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: audit

on:
push:
paths:
- "**/Cargo.toml"
- "**/Cargo.lock"
schedule:
- cron: "0 0 * * *"

jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: cargo audit
working-directory: rust
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-Dwarnings"
62 changes: 62 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: rust

on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened]
branches:
- master

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-Dwarnings"

jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
id: cache-dependencies
with:
path: |
rust/.cargo/registry
rust/.cargo/git
rust/target
key: ${{ runner.os }}-cargo-${{ hashFiles('rust/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: cargo test
working-directory: rust

fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: rustfmt
- run: cargo fmt --all -- --check
working-directory: rust

clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: clippy
- run: cargo clippy --all-targets --all-features
working-directory: rust
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
# Backpack Exchange Api Clients
# Backpack Exchange API

This repository contains the Backpack Exchange API clients for various languages.
<img src="img/backpack.png" width="150px" alt="Backpack" />

## Clients
Access the official API documentation here: [https://docs.backpack.exchange/](https://docs.backpack.exchange/).

[Rust](./rust)
This repository hosts the Backpack Exchange API clients. Currently, the client is only available in [Rust](./rust).

<img src="img/book_example.png" width="270px" alt="Order Book example" />

*Example of an Order Book*

## Contributing

We welcome contributions from the community!
Feel free to open bug reports, suggest new features, or submit pull requests to improve the client and related components.

## License

This project is licensed under the [Apache 2.0 License](LICENSE).
Binary file added img/backpack.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/book_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions rust/.cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[advisories]
ignore = ["RUSTSEC-2023-0033"] # issue in rust_decimal due to borsh
14 changes: 14 additions & 0 deletions rust/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
14 changes: 11 additions & 3 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
[workspace]
members = ["client", "types"]
members = ["client", "examples", "types"]
resolver = "2"

[workspace.package]
keywords = ["backpack", "exchange"]
repository = "https://github.com/backpack-exchange/bpx-api-client"

[workspace.dependencies]
anyhow = "1.0.93"
base64 = "0.22.1"
chrono = { version = "0.4.38", features = ["serde"] }
ed25519-dalek = "2.1.1"
futures-util = "0.3.31"
reqwest = { version = "0.12.5", default-features = false, features = [
"json",
"rustls-tls",
"json",
"rustls-tls",
] }
rust_decimal = "1.35.0"
serde = { version = "1.0.208", features = ["derive"] }
serde_json = "1.0.125"
strum = { version = "0.26.3", features = ["derive"] }
thiserror = "1.0.63"
tokio = { version = "1.41.1", features = ["full"] }
tokio-tungstenite = "0.24.0"
tracing = "0.1.40"
106 changes: 99 additions & 7 deletions rust/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,106 @@
# Backpack Exchange Rust Client
[![Build Badge]][build] [![Crates Badge]][crates] [![Docs Badge]][docs] [![License Badge]][license]

## Table of Contents
[Build Badge]: https://github.com/backpack-exchange/bpx-api-client/actions/workflows/rust.yml/badge.svg
[build]: https://github.com/backpack-exchange/bpx-api-client/actions

- [Usage](#usage)
- [Contributing](#contributing)
[Crates Badge]: https://img.shields.io/crates/v/bpx_api_client.svg
[crates]: https://crates.io/crates/bpx_api_client

[Docs Badge]: https://docs.rs/bpx_api_client/badge.svg
[docs]: https://docs.rs/bpx_api_client

[License Badge]: https://img.shields.io/badge/License-Apache_2.0-blue.svg
[license]: ../LICENSE

# Backpack Exchange API Crate

This crate provides both REST and WebSocket APIs for interacting with the Backpack Exchange:

## Features

- **REST API**: Access public and private (authenticated) endpoints.
- **WebSocket API**: Subscribe to private streams for real-time updates (requires `ws` feature).

The official API documentation is available at [https://docs.backpack.exchange/](https://docs.backpack.exchange/).

## Installation

Add this crate to your `Cargo.toml`:

```toml
[dependencies]
bpx_api_client = "x.y.z" # Replace with the latest version
```

To enable WebSocket support:

```toml
[dependencies]
bpx_api_client = { version = "x.y.z", features = ["ws"] }
```

## Usage

Instructions on how to use the project.
REST API example:

```rust
use bpx_api_client::{BpxClient, BACKPACK_API_BASE_URL};
use std::env;

#[tokio::main]
async fn main() {
let base_url = env::var("BASE_URL").unwrap_or_else(|_| BACKPACK_API_BASE_URL.to_string());
let secret = env::var("SECRET").expect("Missing SECRET environment variable");

let client = BpxClient::init(base_url, secret, None)
.expect("Failed to initialize Backpack API client");

match client.get_open_orders(Some("SOL_USDC")).await {
Ok(orders) => println!("Open Orders: {:?}", orders),
Err(err) => tracing::error!("Error: {:?}", err),
}
}
```

WebSocket API example:

```rust
use anyhow::Result;
use bpx_api_client::{BpxClient, BACKPACK_API_BASE_URL, BACKPACK_WS_URL};
use bpx_api_types::rfq::RequestForQuote;
use std::env;
use tokio::sync::mpsc;

#[tokio::main]
async fn main() -> Result<()> {
let base_url = env::var("BASE_URL").unwrap_or_else(|_| BACKPACK_API_BASE_URL.to_string());
let ws_url = env::var("WS_URL").unwrap_or_else(|_| BACKPACK_WS_URL.to_string());
let secret = env::var("SECRET").expect("Missing SECRET environment variable");

let client = BpxClient::init_with_ws(base_url, ws_url, &secret, None)?;

let (tx, mut rx) = mpsc::channel::<RequestForQuote>(100);
tokio::spawn(async move {
while let Some(rfq) = rx.recv().await {
println!("Received RFQ: {:?}", rfq);
}
});

client.subscribe_to_rfqs(tx).await;

Ok(())
}
```

## Development

This project uses [Just](https://github.com/casey/just) to manage various build and development tasks.

To see the available commands, run:

```shell
just
```

## Contributing
## Crate Usage

Guidelines on how to contribute to the project.
19 changes: 12 additions & 7 deletions rust/client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
[package]
name = "bpx-api-client"
authors = ["Backpack <[email protected]>"]
version = "0.5.0"
license = "Apache-2.0"
version = "0.4.0"
edition = "2021"
description = "Rust client for Backpack Exchange"
repository = "https://github.com/backpack-exchange/bpx-api-client/tree/master/rust/client"
description = "Backpack Exchange API client"
repository = "https://github.com/backpack-exchange/bpx-api-client"

[dependencies]
base64 = { workspace = true }
bpx-api-types = { version = "0.2.0", path = "../types" }
bpx-api-types = { path = "../types" }
ed25519-dalek = { workspace = true }
reqwest = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }

[dev-dependencies]
tokio = { version = "1.39", features = ["full"] }
# Dependencies for the `ws` feature
tokio = { workspace = true, optional = true }
tokio-tungstenite = { workspace = true, optional = true }
futures-util = { workspace = true, optional = true }

[features]
default = []
ws = ["tokio", "tokio-tungstenite", "futures-util"]
53 changes: 35 additions & 18 deletions rust/client/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,54 @@
//! Error handling module for the Backpack Exchange API client.
//!
//! Defines a custom `Error` type and a `Result` type alias to encapsulate
//! various errors that can occur during API interactions.

/// A type alias for `Result` using the custom `Error` type.
pub type Result<T> = std::result::Result<T, Error>;

/// Enum representing possible errors in the Backpack Exchange API client.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Error decoding a base64 string.
#[error(transparent)]
InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
Base64Decode(#[from] base64::DecodeError),

/// Backpack API returned an error with status code and message.
#[error("Backpack API error: {status_code}: {message}")]
BpxApiError {
status_code: reqwest::StatusCode,
message: String,
},

/// Invalid HTTP header value.
#[error(transparent)]
Reqwest(#[from] reqwest::Error),
InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),

#[error("Invalid URL: {0}")]
UrlParseError(String),
/// Represents an invalid request with a custom message.
#[error("Invalid request: {0}")]
InvalidRequest(String),

/// General HTTP client error from `reqwest`.
#[error(transparent)]
SystemTime(#[from] std::time::SystemTimeError),
Reqwest(#[from] reqwest::Error),

/// Invalid secret key provided.
#[error("Invalid secret key")]
SecretKey,

/// Error during JSON serialization or deserialization.
#[error(transparent)]
SerdeJson(#[from] serde_json::error::Error),

/// Error working with system time.
#[error(transparent)]
Utf8(#[from] std::str::Utf8Error),
SystemTime(#[from] std::time::SystemTimeError),

/// UTF-8 decoding error.
#[error(transparent)]
Base64Decode(#[from] base64::DecodeError),

#[error("Invalid secret key")]
SecretKey,

#[error("Invalid request: {0}")]
InvalidRequest(String),
Utf8(#[from] std::str::Utf8Error),

#[error("Backpack API error: {status_code}: {message}")]
BpxApiError {
status_code: reqwest::StatusCode,
message: String,
},
/// Invalid URL format.
#[error("Invalid URL: {0}")]
UrlParseError(String),
}
Loading

0 comments on commit d1a830d

Please sign in to comment.