Documentation Index
Fetch the complete documentation index at: https://docs.lasersell.io/llms.txt
Use this file to discover all available pages before exploring further.
Installation
cargo add lasersell-sdk
cargo add tokio --features full
Modules
| Module | Purpose |
|---|
lasersell_sdk::exit_api | ExitApiClient, request/response types, ExitApiError |
lasersell_sdk::tx | SendTarget, sign_unsigned_tx, send_transaction |
lasersell_sdk::stream::client | StreamClient, StreamConfigure, StreamConnection, StreamSender |
lasersell_sdk::stream::session | StreamSession, position tracking |
lasersell_sdk::stream::proto | Message types (ServerMessage, ClientMessage, StrategyConfigMsg) |
lasersell_sdk::retry | RetryPolicy configuration |
API Client
All methods are async and return Result<T, ExitApiError>.
use lasersell_sdk::exit_api::{ExitApiClient, BuildSellTxRequest, BuildBuyTxRequest};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = ExitApiClient::with_api_key("YOUR_API_KEY");
// Build sell transaction
let sell_request = BuildSellTxRequest {
mint: "TOKEN_MINT".into(),
user_pubkey: "WALLET".into(),
amount_tokens: 1_000_000,
output: SellOutput::Sol,
slippage_bps: 2_000,
..Default::default()
};
let sell_response = client.build_sell_tx(&sell_request).await?;
println!("Sell tx: {}", sell_response.tx);
// Build buy transaction
let buy_request = BuildBuyTxRequest {
mint: "TOKEN_MINT".into(),
user_pubkey: "WALLET".into(),
amount: Some(0.1), // 0.1 SOL
slippage_bps: 2_000,
..Default::default()
};
let buy_response = client.build_buy_tx(&buy_request).await?;
println!("Buy tx: {}", buy_response.tx);
Ok(())
}
Custom Options
use lasersell_sdk::exit_api::{ExitApiClient, ExitApiClientOptions};
use lasersell_sdk::retry::RetryPolicy;
use std::time::Duration;
let options = ExitApiClientOptions {
connect_timeout: Duration::from_millis(500),
attempt_timeout: Duration::from_secs(2),
retry_policy: RetryPolicy {
max_attempts: 3,
initial_backoff: Duration::from_millis(50),
max_backoff: Duration::from_millis(200),
jitter: Duration::from_millis(50),
},
};
let client = ExitApiClient::with_options(Some("YOUR_API_KEY"), options);
Exit Intelligence Stream Session
use lasersell_sdk::stream::client::{StreamClient, StreamConfigure};
use lasersell_sdk::stream::session::{StreamSession, StreamEvent};
use lasersell_sdk::stream::proto::StrategyConfigMsg;
use lasersell_sdk::tx::{SendTarget, sign_unsigned_tx, send_transaction};
use secrecy::SecretString;
use solana_sdk::signature::read_keypair_file;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let keypair = read_keypair_file("./keypair.json")?;
let client = StreamClient::new(SecretString::new(std::env::var("LASERSELL_API_KEY")?));
let session = StreamSession::connect(&client, StreamConfigure {
wallet_pubkeys: vec!["WALLET_PUBKEY".into()],
strategy: StrategyConfigMsg {
target_profit_pct: 5.0,
stop_loss_pct: 1.5,
trailing_stop_pct: Some(3.0),
sell_on_graduation: None,
},
deadline_timeout_sec: Some(45),
send_mode: Some("helius_sender".to_string()),
tip_lamports: Some(1000),
}).await?;
loop {
let event = match session.recv().await {
Some(event) => event,
None => break,
};
match &event {
StreamEvent::ExitSignalWithTx { message, .. } => {
let http = reqwest::Client::new();
let signed = sign_unsigned_tx(&message.unsigned_tx_b64, &keypair)?;
let sig = send_transaction(&http, &SendTarget::HeliusSender, &signed).await?;
println!("Exit submitted: {sig}");
}
StreamEvent::PositionOpened { handle, .. } => {
println!("New position: {}", handle.mint);
}
_ => {}
}
}
Ok(())
}
Liquidity Snapshots and Partial Sells
Tier 1+ only. Requires a Professional or Advanced subscription. See the announcement for full details.
StreamSession caches the latest liquidity snapshot per position. Query slippage bands, maximum sellable amounts, and liquidity trends:
let bands = session.get_slippage_bands(position_id);
let max_tokens = session.get_max_sell_at_slippage(position_id, 500); // 5% slippage
let trend = session.get_liquidity_trend(position_id); // "growing" | "stable" | "draining"
Use build_partial_sell_tx() to sell a portion of a position based on slippage data:
if let Some(max_tokens) = session.get_max_sell_at_slippage(position_id, 500) {
let response = client.build_partial_sell_tx(&handle, max_tokens, 500, "SOL").await?;
}
Mirror Trading
Configure watch wallets to mirror trades from other wallets. When a watched wallet opens a position on a supported market, the stream sends a MirrorBuySignal event with an unsigned transaction for your wallet to execute.
use lasersell_sdk::stream::client::{StreamClient, StreamConfigure};
use lasersell_sdk::stream::session::{StreamSession, StreamEvent};
use lasersell_sdk::stream::proto::{
StrategyConfigMsg, WatchWalletConfig, AutoBuyConfig, MirrorConfig,
};
use lasersell_sdk::tx::{SendTarget, sign_unsigned_tx, send_transaction};
use secrecy::SecretString;
use solana_sdk::signature::read_keypair_file;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let keypair = read_keypair_file("./keypair.json")?;
let wallet_pubkey = "YOUR_WALLET_PUBKEY".to_string();
let client = StreamClient::new(SecretString::new(std::env::var("LASERSELL_API_KEY")?));
let session = StreamSession::connect(&client, StreamConfigure {
wallet_pubkeys: vec![wallet_pubkey.clone()],
strategy: StrategyConfigMsg {
target_profit_pct: 50.0,
stop_loss_pct: 25.0,
trailing_stop_pct: None,
sell_on_graduation: None,
},
deadline_timeout_sec: Some(45),
send_mode: Some("helius_sender".to_string()),
tip_lamports: Some(1000),
watch_wallets: Some(vec![
WatchWalletConfig {
pubkey: "WatchedWalletPubkey...".into(),
auto_buy: Some(AutoBuyConfig {
wallet_pubkey: wallet_pubkey.clone(),
amount_quote_units: Some(100_000_000),
amount_usd1_units: None,
}),
mirror_sell: false,
},
]),
mirror_config: Some(MirrorConfig {
max_positions_per_wallet: 1,
cooldown_sec: 30,
max_active_sol: 5.0,
buy_slippage_bps: 2500,
}),
}).await?;
let http = reqwest::Client::new();
loop {
let event = match session.recv().await {
Some(event) => event,
None => break,
};
match &event {
StreamEvent::MirrorBuySignal { message, .. } => {
let signed = sign_unsigned_tx(&message.unsigned_tx_b64, &keypair)?;
let sig = send_transaction(&http, &SendTarget::HeliusSender, &signed).await?;
session.sender().mirror_buy_result(&message.mint, true);
println!("Mirror buy submitted: {sig}");
}
StreamEvent::MirrorBuyFailed { message, .. } => {
eprintln!("Mirror buy failed: {}", message.reason);
}
StreamEvent::ExitSignalWithTx { message, .. } => {
let signed = sign_unsigned_tx(&message.unsigned_tx_b64, &keypair)?;
let sig = send_transaction(&http, &SendTarget::HeliusSender, &signed).await?;
println!("Exit submitted: {sig}");
}
_ => {}
}
}
Ok(())
}
The watch_wallets field specifies which wallets to mirror. Each WatchWalletConfig includes an auto_buy configuration that controls how much to spend when mirroring a trade, and a mirror_sell flag that determines whether to also mirror sell transactions.
The MirrorConfig struct sets global limits: max_positions_per_wallet caps concurrent mirrored positions, cooldown_sec enforces a delay between mirror buys, max_active_sol limits total SOL exposure, and buy_slippage_bps sets the slippage tolerance for mirror buy transactions.
Transaction Helpers
use lasersell_sdk::tx::{
SendTarget,
sign_unsigned_tx,
send_transaction,
astralane_iris_url,
MAINNET_BETA_RPC_URL,
};
// Sign
let signed_tx = sign_unsigned_tx(&unsigned_tx_b64, &keypair)?;
// Create an HTTP client (reuse across calls)
let http = reqwest::Client::new();
// Send via Helius Sender
let sig = send_transaction(&http, &SendTarget::HeliusSender, &signed_tx).await?;
// Send via custom RPC
let sig = send_transaction(
&http,
&SendTarget::Rpc { url: "https://rpc.example.com".into() },
&signed_tx,
).await?;
// Send via Astralane
let sig = send_transaction(
&http,
&SendTarget::Astralane {
api_key: "KEY".into(),
region: Some("fr".into()),
},
&signed_tx,
).await?;
Error Handling
use lasersell_sdk::exit_api::ExitApiError;
use lasersell_sdk::tx::TxSubmitError;
match client.build_sell_tx(&request).await {
Ok(response) => println!("tx: {}", response.tx),
Err(e) => {
eprintln!("Error kind: {:?}", e.kind());
eprintln!("Retryable: {}", e.is_retryable());
}
}
Complete Example
See the Quickstart for a full working example.