Rust
Complete examples for integrating Turnpike API with Rust.
Dependencies
Add to Cargo.toml:
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
solana-client = "1.16"
solana-sdk = "1.16"
base64 = "0.21"
anyhow = "1.0"Lightning API Examples
Execute Buy Trade
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::env;
#[derive(Serialize)]
struct BuyTradeRequest {
#[serde(rename = "publicKey")]
public_key: String,
mint: String,
amount: f64,
slippage: f64,
#[serde(rename = "priorityFee")]
priority_fee: f64,
}
#[derive(Deserialize, Debug)]
struct BuyTradeResponse {
success: bool,
signature: String,
#[serde(rename = "tokensReceived")]
tokens_received: u64,
#[serde(rename = "effectivePrice")]
effective_price: f64,
}
async fn execute_buy_trade(
public_key: &str,
mint: &str,
amount: f64,
) -> Result<BuyTradeResponse, Box<dyn std::error::Error>> {
let client = Client::new();
let api_key = env::var("TURNPIKE_API_KEY")?;
let request = BuyTradeRequest {
public_key: public_key.to_string(),
mint: mint.to_string(),
amount,
slippage: 10.0,
priority_fee: 0.0001,
};
let response = client
.post("https://api.turnpike.dev/trade/buy")
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", api_key))
.json(&request)
.send()
.await?;
let data: BuyTradeResponse = response.json().await?;
println!("Trade successful!");
println!("Signature: {}", data.signature);
println!("Tokens received: {}", data.tokens_received);
println!("Effective price: {}", data.effective_price);
Ok(data)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let result = execute_buy_trade(
"YOUR_WALLET_PUBLIC_KEY",
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
0.01,
)
.await?;
println!("Result: {:?}", result);
Ok(())
}Get Token Information
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct TokenInfo {
mint: String,
symbol: String,
name: String,
decimals: u8,
price: f64,
#[serde(rename = "marketCap")]
market_cap: f64,
#[serde(rename = "volume24h")]
volume_24h: f64,
}
async fn get_token_info(mint: &str) -> Result<TokenInfo, Box<dyn std::error::Error>> {
let client = Client::new();
let api_key = env::var("TURNPIKE_API_KEY")?;
let url = format!("https://api.turnpike.dev/token/info/{}", mint);
let response = client
.get(&url)
.header("Authorization", format!("Bearer {}", api_key))
.send()
.await?;
let info: TokenInfo = response.json().await?;
println!("{}: ${}", info.symbol, info.price);
println!("Market Cap: ${}", info.market_cap);
Ok(info)
}Get Portfolio
#[derive(Deserialize, Debug)]
struct Portfolio {
#[serde(rename = "publicKey")]
public_key: String,
#[serde(rename = "totalValueUsd")]
total_value_usd: f64,
#[serde(rename = "solBalance")]
sol_balance: f64,
tokens: Vec<TokenHolding>,
}
#[derive(Deserialize, Debug)]
struct TokenHolding {
mint: String,
symbol: String,
balance: f64,
#[serde(rename = "valueUsd")]
value_usd: f64,
}
async fn get_portfolio(public_key: &str) -> Result<Portfolio, Box<dyn std::error::Error>> {
let client = Client::new();
let api_key = env::var("TURNPIKE_API_KEY")?;
let url = format!("https://api.turnpike.dev/portfolio/{}", public_key);
let response = client
.get(&url)
.header("Authorization", format!("Bearer {}", api_key))
.send()
.await?;
let portfolio: Portfolio = response.json().await?;
println!("Total Value: ${:.2}", portfolio.total_value_usd);
println!("SOL Balance: {}", portfolio.sol_balance);
println!("Tokens: {}", portfolio.tokens.len());
for token in &portfolio.tokens {
println!(" {}: {} (${:.2})", token.symbol, token.balance, token.value_usd);
}
Ok(portfolio)
}Local Transaction API Examples
Build and Sign Transaction
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
signature::{Keypair, Signer},
transaction::Transaction,
};
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
#[derive(Deserialize)]
struct TransactionResponse {
transaction: String,
#[serde(rename = "lastValidBlockHeight")]
last_valid_block_height: u64,
}
async fn build_and_sign_trade(
wallet: &Keypair,
mint: &str,
amount: f64,
) -> Result<String, Box<dyn std::error::Error>> {
let client = Client::new();
let api_key = env::var("TURNPIKE_API_KEY")?;
// 1. Build transaction via API
let request = serde_json::json!({
"publicKey": wallet.pubkey().to_string(),
"mint": mint,
"amount": amount,
"slippage": 10.0
});
let response = client
.post("https://api.turnpike.dev/transaction/buy")
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", api_key))
.json(&request)
.send()
.await?;
let data: TransactionResponse = response.json().await?;
// 2. Deserialize transaction
let transaction_bytes = BASE64.decode(&data.transaction)?;
let mut transaction: Transaction = bincode::deserialize(&transaction_bytes)?;
// 3. Connect to RPC
let rpc_client = RpcClient::new("https://api.mainnet-beta.solana.com".to_string());
// 4. Sign transaction
let recent_blockhash = rpc_client.get_latest_blockhash()?;
transaction.sign(&[wallet], recent_blockhash);
// 5. Send transaction
let signature = rpc_client.send_and_confirm_transaction(&transaction)?;
println!("Transaction sent: {}", signature);
Ok(signature.to_string())
}WebSocket Examples
Basic WebSocket Connection
Add to Cargo.toml:
tokio-tungstenite = "0.20"
futures-util = "0.3"use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
use futures_util::{StreamExt, SinkExt};
use serde_json::json;
async fn stream_trades(api_key: String) -> Result<(), Box<dyn std::error::Error>> {
let url = "wss://turnpike.dev/api/data";
let (ws_stream, _) = connect_async(url).await?;
let (mut write, mut read) = ws_stream.split();
// Authenticate
write.send(Message::Text(
json!({
"method": "authenticate",
"apiKey": api_key
})
.to_string()
)).await?;
// Subscribe to trades
write.send(Message::Text(
json!({
"method": "subscribe",
"keys": ["trades"]
})
.to_string()
)).await?;
// Listen for messages
while let Some(msg) = read.next().await {
match msg? {
Message::Text(text) => {
let data: serde_json::Value = serde_json::from_str(&text)?;
if data["type"] == "trade" {
println!(
"Trade: {} {} @ ${}",
data["side"],
data["amount"],
data["price"]
);
}
}
Message::Close(_) => break,
_ => {}
}
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = env::var("TURNPIKE_API_KEY")?;
stream_trades(api_key).await?;
Ok(())
}Complete Trading Bot Example
use std::collections::HashMap;
use tokio::sync::mpsc;
#[derive(Debug)]
struct PriceUpdate {
mint: String,
price: f64,
}
struct TradingBot {
api_key: String,
public_key: String,
targets: HashMap<String, f64>,
}
impl TradingBot {
fn new(api_key: String, public_key: String) -> Self {
Self {
api_key,
public_key,
targets: HashMap::new(),
}
}
fn add_target(&mut self, mint: String, target_price: f64) {
self.targets.insert(mint, target_price);
}
async fn execute_buy(&self, mint: &str, amount: f64) -> Result<String, Box<dyn std::error::Error>> {
let client = Client::new();
let request = serde_json::json!({
"publicKey": self.public_key,
"mint": mint,
"amount": amount,
"slippage": 15.0
});
let response = client
.post("https://api.turnpike.dev/trade/buy")
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", self.api_key))
.json(&request)
.send()
.await?;
let data: BuyTradeResponse = response.json().await?;
println!("Buy executed: {}", data.signature);
Ok(data.signature)
}
async fn handle_price_update(&mut self, update: PriceUpdate) {
if let Some(&target_price) = self.targets.get(&update.mint) {
if update.price <= target_price {
println!("Target price reached for {}!", update.mint);
if let Ok(_) = self.execute_buy(&update.mint, 0.01).await {
self.targets.remove(&update.mint);
}
}
}
}
async fn start(mut self) -> Result<(), Box<dyn std::error::Error>> {
let url = "wss://turnpike.dev/api/data";
let (ws_stream, _) = connect_async(url).await?;
let (mut write, mut read) = ws_stream.split();
// Authenticate
write.send(Message::Text(
json!({
"method": "authenticate",
"apiKey": self.api_key
})
.to_string()
)).await?;
// Subscribe
write.send(Message::Text(
json!({
"method": "subscribe",
"keys": ["priceUpdates"]
})
.to_string()
)).await?;
// Process messages
while let Some(msg) = read.next().await {
if let Ok(Message::Text(text)) = msg {
let data: serde_json::Value = serde_json::from_str(&text)?;
if data["type"] == "priceUpdate" {
let update = PriceUpdate {
mint: data["mint"].as_str().unwrap().to_string(),
price: data["price"].as_f64().unwrap(),
};
self.handle_price_update(update).await;
}
}
}
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut bot = TradingBot::new(
env::var("TURNPIKE_API_KEY")?,
"YOUR_WALLET_PUBLIC_KEY".to_string(),
);
bot.add_target("TOKEN_MINT_1".to_string(), 0.00001);
bot.add_target("TOKEN_MINT_2".to_string(), 0.00005);
bot.start().await?;
Ok(())
}Error Handling Example
use anyhow::{Context, Result};
use thiserror::Error;
#[derive(Error, Debug, Deserialize)]
#[error("{message}")]
struct APIError {
code: String,
message: String,
#[serde(default)]
details: serde_json::Value,
}
async fn execute_trade_with_retry(
mut params: serde_json::Value,
max_retries: u32,
) -> Result<BuyTradeResponse> {
let client = Client::new();
let api_key = env::var("TURNPIKE_API_KEY")?;
for attempt in 0..max_retries {
let response = client
.post("https://api.turnpike.dev/trade/buy")
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", api_key))
.json(¶ms)
.send()
.await?;
if response.status().is_success() {
return Ok(response.json().await?);
}
let error: serde_json::Value = response.json().await?;
let api_error: APIError = serde_json::from_value(error["error"].clone())?;
match api_error.code.as_str() {
"RATE_LIMIT_EXCEEDED" => {
let wait_time = 2u64.pow(attempt);
println!("Rate limited, waiting {}s...", wait_time);
tokio::time::sleep(tokio::time::Duration::from_secs(wait_time)).await;
continue;
}
"SLIPPAGE_EXCEEDED" if attempt < max_retries - 1 => {
if let Some(slippage) = params["slippage"].as_f64() {
params["slippage"] = serde_json::json!(slippage * 1.5);
println!("Increasing slippage to {}", params["slippage"]);
continue;
}
}
_ => return Err(anyhow::anyhow!("{}", api_error)),
}
}
Err(anyhow::anyhow!("Failed after {} attempts", max_retries))
}Last updated