| Crates.io | nadfun_sdk |
| lib.rs | nadfun_sdk |
| version | 0.3.11 |
| created_at | 2025-08-18 07:50:50.009565+00 |
| updated_at | 2025-12-23 15:51:32.793304+00 |
| description | Rust SDK for Nad.fun |
| homepage | |
| repository | https://github.com/Naddotfun/nadfun-sdk-rust |
| max_upload_size | |
| id | 1800057 |
| size | 525,020 |
A comprehensive Rust SDK for interacting with Nad.fun ecosystem contracts, including bonding curves, DEX trading, and real-time event monitoring.
Add this to your Cargo.toml:
[dependencies]
nadfun_sdk = "0.3.5"
use nadfun_sdk::prelude::*; // Import everything you need
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
let rpc_url = "https://your-rpc-endpoint".to_string();
let private_key = "your_private_key_here".to_string();
// Initialize Core - set network once, it's used everywhere automatically
let core = Core::new(rpc_url.clone(), private_key.clone(), Network::Mainnet).await?;
// 1. Get quote for buying tokens
let token: Address = "0x...".parse()?;
let mon_amount = parse_ether("0.1")?; // Buy with 0.1 MON
let (router, expected_tokens) = core.get_amount_out(token, mon_amount, true).await?;
// 2. Apply slippage protection (5%)
let min_tokens = SlippageUtils::calculate_amount_out_min(expected_tokens, 5.0);
// 3. Estimate gas
let gas_params = GasEstimationParams::Buy {
token,
amount_in: mon_amount,
amount_out_min: min_tokens,
to: core.wallet_address(),
deadline: U256::from(9999999999999999u64),
};
let estimated_gas = core.estimate_gas(&router, gas_params).await?;
let gas_with_buffer = estimated_gas * 120 / 100; // Add 20% buffer
// 4. Execute buy
let buy_params = BuyParams {
token,
amount_in: mon_amount,
amount_out_min: min_tokens,
to: core.wallet_address(),
deadline: U256::from(9999999999999999u64),
gas_limit: Some(gas_with_buffer),
gas_price: None, // Or use Some(GasPricing::Eip1559 { ... })
nonce: None, // Auto-increment
};
// Execute buy - returns tx_hash immediately
let tx_hash = core.buy(buy_params, router).await?;
println!("Transaction submitted: {}", tx_hash);
// Optionally wait for receipt to check status
let receipt = core.get_receipt(tx_hash).await?;
println!("Transaction confirmed in block: {:?}", receipt.block_number);
println!("Gas used: {:?}", receipt.gas_used);
println!("Status: {}", if receipt.status { "Success" } else { "Failed" });
Ok(())
}
Create new tokens with automatic image upload, metadata storage, and initial buy:
use nadfun_sdk::{ActionId, Core, CreateTokenParams, Network};
use alloy::primitives::utils::parse_ether;
// Initialize Core
let core = Core::new(rpc_url, private_key, Network::Mainnet).await?;
// Calculate initial buy amount
let initial_buy_mon = parse_ether("1.5")?;
let amount_out = core.get_initial_buy_amount_out(initial_buy_mon).await?;
// Create token with all metadata
let params = CreateTokenParams {
name: "My Token".to_string(),
symbol: "MTK".to_string(),
description: "My awesome token".to_string(),
image_uri: "https://i.imgur.com/yourimage.png".to_string(),
website: Some("https://mytoken.com".to_string()),
twitter: Some("https://x.com/mytoken".to_string()),
telegram: Some("https://t.me/mytoken".to_string()),
creator_address: core.wallet_address(),
amount_out,
value: initial_buy_mon,
action_id: ActionId::CapricornActor, // Choose CapricornActor (1) or AmplifyActor (2)
};
let result = core.create_token(params).await?;
println!("Token created at: {}", result.token_address);
Features:
ActionId enumExecute buy/sell operations on bonding curves with slippage protection:
use nadfun_sdk::{Trade, SlippageUtils, GasEstimationParams, types::BuyParams};
// Get quote and execute buy
let (router, expected_tokens) = core.get_amount_out(token, mon_amount, true).await?;
let min_tokens = SlippageUtils::calculate_amount_out_min(expected_tokens, 5.0);
// Use new unified gas estimation system
let gas_params = GasEstimationParams::Buy {
token,
amount_in: mon_amount,
amount_out_min: min_tokens,
to: wallet_address,
deadline: U256::from(deadline),
};
// Get accurate gas estimation from network
let estimated_gas = core.estimate_gas(&router, gas_params).await?;
let gas_with_buffer = estimated_gas * 120 / 100; // Add 20% buffer
let buy_params = BuyParams {
token,
amount_in: mon_amount,
amount_out_min: min_tokens,
to: wallet_address,
deadline: U256::from(deadline),
gas_limit: Some(gas_with_buffer), // Use network-based estimation
gas_price: Some(GasPricing::LegacyWithPrice { gas_price: 50_000_000_000 }), // 50 gwei
nonce: None, // Auto-detect
};
// Execute buy - returns tx_hash immediately (fast!)
let tx_hash = core.buy(buy_params, router).await?;
println!("Transaction submitted: {}", tx_hash);
// Later, check the transaction status if needed
let receipt = core.get_receipt(tx_hash).await?;
if receipt.status {
println!("Trade successful! Gas used: {:?}", receipt.gas_used);
}
New in v0.3.0: All trading functions now return transaction hash immediately without waiting for confirmation. This makes your trading bot much faster!
// OLD - Waits for confirmation (slow)
let result = core.buy(params, router).await?; // Waits ~2-15 seconds
// NEW - Returns immediately (fast!)
let tx_hash = core.buy(params, router).await?; // Returns in milliseconds
println!("Submitted: {}", tx_hash);
// Check status later when you need it
let receipt = core.get_receipt(tx_hash).await?;
println!("Confirmed: {}", receipt.status);
v0.2.0 introduces a unified gas estimation system that replaces static constants with real-time network estimation.
v0.3.0 adds EIP-1559 gas pricing support for better transaction fee control:
use nadfun_sdk::types::GasPricing;
// Option 1: Legacy (default) - uses network gas price
let gas_price = Some(GasPricing::Legacy);
// Option 2: Legacy with explicit gas price
let gas_price = Some(GasPricing::LegacyWithPrice {
gas_price: 50_000_000_000, // 50 gwei
});
// Option 3: EIP-1559 (recommended for Monad)
let gas_price = Some(GasPricing::Eip1559 {
max_fee_per_gas: 100_000_000_000, // 100 gwei max
max_priority_fee_per_gas: 2_000_000_000, // 2 gwei tip
});
// Use in BuyParams/SellParams
let buy_params = BuyParams {
// ... other fields
gas_price, // Unified gas pricing field
nonce: None,
};
use nadfun_sdk::{GasEstimationParams, Trade};
// Create gas estimation parameters for any operation
let gas_params = GasEstimationParams::Buy {
token,
amount_in: mon_amount,
amount_out_min: min_tokens,
to: wallet_address,
deadline: U256::from(deadline),
};
// Get real-time gas estimation from network
let estimated_gas = core.estimate_gas(&router, gas_params).await?;
// Apply buffer strategy
let gas_with_buffer = estimated_gas * 120 / 100; // 20% buffer
pub enum GasEstimationParams {
// For buying tokens
Buy { token, amount_in, amount_out_min, to, deadline },
// For selling tokens (requires token approval)
Sell { token, amount_in, amount_out_min, to, deadline },
// For gasless selling with permits
SellPermit { token, amount_in, amount_out_min, to, deadline, v, r, s },
}
The new system automatically handles common issues:
// Fixed buffer amounts
let gas_fixed_buffer = estimated_gas + 50_000; // +50k gas
// Percentage-based buffers
let gas_20_percent = estimated_gas * 120 / 100; // 20% buffer
let gas_25_percent = estimated_gas * 125 / 100; // 25% buffer (for complex operations)
// Choose based on operation complexity
let final_gas = match operation_type {
"buy" => estimated_gas * 120 / 100, // 20% buffer
"sell" => estimated_gas * 115 / 100, // 15% buffer
"sell_permit" => estimated_gas * 125 / 100, // 25% buffer
_ => estimated_gas + 50_000, // Fixed buffer
};
// OLD (v0.1.x) - Static constants
use nadfun_sdk::{BondingCurveGas, get_default_gas_limit, Operation};
let gas_limit = get_default_gas_limit(&router, Operation::Buy);
// NEW (v0.2.0) - Network-based estimation
use nadfun_sdk::GasEstimationParams;
let params = GasEstimationParams::Buy { token, amount_in, amount_out_min, to, deadline };
let estimated_gas = core.estimate_gas(&router, params).await?;
let gas_limit = estimated_gas * 120 / 100; // Apply buffer
⚠️ Important Notes:
Interact with ERC-20 tokens and get metadata:
use nadfun_sdk::TokenHelper;
let token_helper = TokenHelper::new(rpc_url, private_key).await?;
// Get token metadata
let metadata = token_helper.get_token_metadata(token).await?;
println!("Token: {} ({})", metadata.name, metadata.symbol);
// Check balances and allowances
let balance = token_helper.balance_of(token, wallet).await?;
let allowance = token_helper.allowance(token, owner, spender).await?;
// Approve tokens
let tx = token_helper.approve(token, spender, amount).await?;
Monitor bonding curve and DEX events in real-time:
use nadfun_sdk::stream::CurveStream;
use nadfun_sdk::types::{BondingCurveEvent, EventType};
use futures_util::{pin_mut, StreamExt};
// Create WebSocket stream
let curve_stream = CurveStream::new("wss://your-ws-endpoint".to_string()).await?;
// Configure filters (optional)
let curve_stream = curve_stream
.subscribe_events(vec![EventType::Buy, EventType::Sell])
.filter_tokens(vec![token_address]);
// Subscribe and process events
let stream = curve_stream.subscribe().await?;
pin_mut!(stream);
while let Some(event_result) = stream.next().await {
match event_result {
Ok(event) => {
println!("Event: {:?} for token {}", event.event_type(), event.token());
}
Err(e) => println!("Error: {}", e),
}
}
use nadfun_sdk::stream::UniswapSwapStream;
use futures_util::{pin_mut, StreamExt};
// Auto-discover pools for tokens
let swap_stream = UniswapSwapStream::discover_pools_for_tokens(
"wss://your-ws-endpoint".to_string(),
vec![token_address]
).await?;
// Subscribe and process events
let stream = swap_stream.subscribe().await?;
pin_mut!(stream);
while let Some(event_result) = stream.next().await {
match event_result {
Ok(event) => {
println!("Swap in pool {}: {} -> {}",
event.pool_address, event.amount0, event.amount1);
}
Err(e) => println!("Error: {}", e),
}
}
Fetch and analyze historical events:
use nadfun_sdk::stream::{CurveIndexer, EventType};
let provider = Arc::new(ProviderBuilder::new().connect_http(http_url.parse()?));
let indexer = CurveIndexer::new(provider);
// Fetch events from block range
let events = indexer.fetch_events(
18_000_000,
18_010_000,
vec![EventType::Create, EventType::Buy],
None // all tokens
).await?;
println!("Found {} events", events.len());
Find Capricorn CL pool addresses for tokens:
use nadfun_sdk::stream::UniswapSwapIndexer;
// Auto-discover pools for multiple tokens
let indexer = UniswapSwapIndexer::discover_pools_for_tokens(provider, tokens).await?;
let pools = indexer.pool_addresses();
// Discover pool for single token
let indexer = UniswapSwapIndexer::discover_pool_for_token(provider, token).await?;
Monitor Capricorn CL swap events:
use nadfun_sdk::stream::UniswapSwapIndexer;
// Auto-discover pools for tokens
let indexer = UniswapSwapIndexer::discover_pools_for_tokens(provider, tokens).await?;
let swaps = indexer.fetch_events(from_block, to_block).await?;
for swap in swaps {
println!("Swap in pool {}: {} -> {}",
swap.pool_metadata.pool_address,
swap.amount0,
swap.amount1
);
}
The SDK includes comprehensive examples in the examples/ directory:
# Create a new token
cargo run --example create_token -- \
--private-key your_private_key \
--rpc-url https://your-rpc-url \
--network mainnet \
--name "My Token" \
--symbol "MTK" \
--description "My awesome token" \
--image-uri "https://i.imgur.com/yourimage.png" \
--initial-buy "1.5"
# Using environment variables
export PRIVATE_KEY="your_private_key_here"
export RPC_URL="https://your-rpc-endpoint"
export TOKEN="0xTokenAddress"
export RECIPIENT="0xRecipientAddress" # For token operations
cargo run --example buy # Buy tokens with network-based gas estimation
cargo run --example sell # Sell tokens with automatic approval handling
cargo run --example sell_permit # Gasless sell with real permit signatures
cargo run --example gas_estimation # Comprehensive gas estimation example
cargo run --example basic_operations # Token operations (requires recipient)
# Using command line arguments
cargo run --example buy -- --private-key your_private_key_here --rpc-url https://your-rpc-endpoint --token 0xTokenAddress
cargo run --example sell -- --private-key your_private_key_here --rpc-url https://your-rpc-endpoint --token 0xTokenAddress
cargo run --example sell_permit -- --private-key your_private_key_here --rpc-url https://your-rpc-endpoint --token 0xTokenAddress
cargo run --example gas_estimation -- --private-key your_private_key_here --rpc-url https://your-rpc-endpoint --token 0xTokenAddress
cargo run --example basic_operations -- --private-key your_private_key_here --rpc-url https://your-rpc-endpoint --token 0xTokenAddress --recipient 0xRecipientAddress
# Comprehensive gas estimation with automatic problem solving
cargo run --example gas_estimation -- --private-key your_private_key_here --rpc-url https://your-rpc-endpoint --token 0xTokenAddress
Features:
core.estimate_gas() for all operation typescargo run --example basic_operations # Basic ERC-20 operations
cargo run --example permit_signature # EIP-2612 permit signatures
The SDK provides 5 comprehensive streaming examples organized by category:
1. curve_indexer - Historical bonding curve event analysis
# Fetch historical Create, Buy, Sell events
cargo run --example curve_indexer -- --rpc-url https://your-rpc-endpoint
# With specific tokens and time range
cargo run --example curve_indexer -- \
--rpc-url https://your-rpc-endpoint \
--tokens 0xToken1,0xToken2
2. curve_stream - Real-time bonding curve monitoring
# Scenario 1: Monitor all bonding curve events
cargo run --example curve_stream -- --ws-url wss://your-ws-endpoint
# Scenario 2: Filter specific event types (Buy/Sell only)
EVENTS=Buy,Sell cargo run --example curve_stream -- --ws-url wss://your-ws-endpoint
# Scenario 3: Filter specific tokens only
cargo run --example curve_stream -- \
--ws-url wss://your-ws-endpoint \
--tokens 0xToken1,0xToken2
# Scenario 4: Combined filtering (events AND tokens)
EVENTS=Buy,Sell cargo run --example curve_stream -- \
--ws-url wss://your-ws-endpoint \
--tokens 0xToken1
Features:
EVENTS environment variable--tokens argument3. dex_indexer - Historical DEX swap data analysis
# Discover pools and fetch historical swap events
cargo run --example dex_indexer -- \
--rpc-url https://your-rpc-endpoint \
--tokens 0xToken1,0xToken2
# Batch process with JSON array format
cargo run --example dex_indexer -- \
--rpc-url https://your-rpc-endpoint \
--tokens '["0xToken1","0xToken2"]'
4. dex_stream - Real-time DEX swap monitoring
# Scenario 1: Monitor specific pool addresses directly
POOLS=0xPool1,0xPool2 cargo run --example dex_stream -- --ws-url wss://your-ws-endpoint
# Scenario 2: Auto-discover pools for multiple tokens
cargo run --example dex_stream -- \
--ws-url wss://your-ws-endpoint \
--tokens 0xToken1,0xToken2
# Scenario 3: Single token pool discovery
cargo run --example dex_stream -- \
--ws-url wss://your-ws-endpoint \
--token 0xTokenAddress
Features:
5. pool_discovery - Automated pool address discovery
# Find Capricorn CL pools for multiple tokens
cargo run --example pool_discovery -- \
--rpc-url https://your-rpc-endpoint \
--tokens 0xToken1,0xToken2
# Discover pools for single token
cargo run --example pool_discovery -- \
--rpc-url https://your-rpc-endpoint \
--token 0xTokenAddress
All examples have been tested and verified working. Here are ready-to-run test commands:
# Test bonding curve streaming (all events)
cargo run --example curve_stream -- --ws-url wss://your-ws-endpoint
# Test DEX swap streaming (auto-discover pools)
cargo run --example dex_stream -- \
--ws-url wss://your-ws-endpoint \
--tokens 0xYourTokenAddress
# Test with event filtering
EVENTS=Buy,Sell cargo run --example curve_stream -- --ws-url wss://your-ws-endpoint
# Test with specific pool monitoring
POOLS=0xPool1,0xPool2 cargo run --example dex_stream -- --ws-url wss://your-ws-endpoint
# Test bonding curve historical analysis
cargo run --example curve_indexer -- \
--rpc-url https://your-rpc-endpoint \
--tokens 0xYourTokenAddress
# Test pool discovery
cargo run --example pool_discovery -- \
--rpc-url https://your-rpc-endpoint \
--tokens 0xToken1,0xToken2
# Test DEX historical analysis
cargo run --example dex_indexer -- \
--rpc-url https://your-rpc-endpoint \
--tokens 0xYourTokenAddress
# Minimal test - just connect and verify
cargo run --example curve_stream -- --ws-url wss://your-ws-endpoint
# Should output: "Listening for ALL bonding curve events..."
cargo run --example dex_stream -- --token 0xTokenAddress --ws-url wss://your-ws-endpoint
# Should output: "Discovered X pools for 1 tokens"
BondingCurveEvent: Unified enum for all bonding curve events
Create, Buy, Sell, Sync, Lock, Listed variants.token(), .event_type(), .block_number(), .transaction_index()SwapEvent: Capricorn CL swap events with complete metadata
pool_address, amount0, amount1, sender, recipient, liquidity, tick, sqrt_price_x96EventType: Enum for filtering bonding curve events
Create, Buy, Sell, Sync, Lock, ListedCurveStream: Bonding curve event streaming
.subscribe_events(), .filter_tokens(), .subscribe()Pin<Box<dyn Stream<Item = Result<BondingCurveEvent>> + Send>>UniswapSwapStream: DEX swap event streaming
.new(), .discover_pools_for_tokens(), .discover_pool_for_token(), .subscribe()Pin<Box<dyn Stream<Item = Result<SwapEvent>> + Send>>BuyParams / SellParams: Parameters for buy/sell operationsTradeResult: Transaction result with status and metadataSlippageUtils: Utilities for slippage calculationsTokenMetadata: Name, symbol, decimals, total supplyPermitSignature: EIP-2612 permit signature dataexport RPC_URL="https://your-rpc-endpoint"
export PRIVATE_KEY="your_private_key_here"
export WS_URL="wss://your-ws-endpoint"
export TOKEN="0xTokenAddress"
export TOKENS="0xToken1,0xToken2" # Multiple tokens for monitoring
export RECIPIENT="0xRecipientAddress"
All examples support command line arguments for configuration:
# Available options
--rpc-url <URL> # RPC URL (default: https://your-rpc-endpoint)
--ws-url <URL> # WebSocket URL (default: wss://your-ws-endpoint)
--private-key <KEY> # Private key for transactions
--token <ADDRESS> # Token address for operations
--tokens <ADDRS> # Token addresses: 'addr1,addr2' or '["addr1","addr2"]'
--recipient <ADDR> # Recipient address for transfers/allowances
--help, -h # Show help
# Example usage
cargo run --example sell_permit -- \
--rpc-url https://your-rpc-endpoint \
--private-key your_private_key_here \
--token 0xYourTokenAddress
# Example with recipient (for token operations)
cargo run --example basic_operations -- \
--private-key your_private_key_here \
--rpc-url https://your-rpc-endpoint \
--token 0xYourTokenAddress \
--recipient 0xRecipientAddress
# Example with multiple tokens for monitoring
cargo run --example dex_indexer -- \
--rpc-url https://your-rpc-endpoint \
--tokens 0xToken1,0xToken2,0xToken3
# Example with JSON array format
cargo run --example pool_discovery -- \
--rpc-url https://your-rpc-endpoint \
--tokens '["0xToken1","0xToken2"]'
All contract addresses are defined in constants.rs:
0x6B5F564339DbAD6b780249827f2198a841FEB7F30x3bd359C1119dA7Da1D913D1C4D2B7c461115433A0xA7283d07812a02AFB7C09B60f8896bCEA3F90aCE0x6F6B8F1a20703309951a5127c45B49b1CD981A220x0B79d71AE99528D1dB24A4148b5f4F865cc2b1370x7e78A8DE94f21804F7a17F4E8BF9EC2c872187ea0xE6dc50f36E26bAfC5f103021e01EF111402Cd9400x760AfE86e5de5fa0Ee542fc7B7B713e1c54257010xbD40afc47F0a42680819513d556C2eBCcd1eBC680xC703bCe420882b1A35428773B92731adCB4a1f7f0x65586647FC66221c5f208F9b8FC0A93C72e3a5980x181B05cD8D73564A22C17825F3413A0f30634CCFThe SDK uses anyhow::Result for error handling:
use anyhow::Result;
async fn example() -> Result<()> {
let core = Core::new(rpc_url, private_key, Network::Mainnet).await?;
let result = core.get_amount_out(token, amount, true).await?;
Ok(())
}
Result<Event> patternMIT License - see LICENSE for details.