StealthPayment
Represents a detected incoming payment. Returned by the Scanner when it finds payments addressed to your meta-address.
Quick Overview
onyx_sdk::coreClone, Debug, SerializeDefinition
pub struct StealthPayment {
/// The stealth address where funds were received
pub stealth_address: Pubkey,
/// Ephemeral public key from the sender
pub ephemeral_pubkey: [u8; 32],
/// Current balance in lamports
pub balance: u64,
/// Unix timestamp when the payment was announced
pub timestamp: i64,
/// Optional: Associated token account if this is an SPL token payment
pub token_account: Option<Pubkey>,
/// Optional: Token mint if this is an SPL token payment
pub token_mint: Option<Pubkey>,
}Fields
stealth_addressPubkeyThe one-time Solana address where funds were deposited. This is a unique address generated specifically for this payment.
ephemeral_pubkey[u8; 32]The sender's one-time public key used to derive this stealth address. Required to derive the spending keypair.
balanceu64Current balance of the stealth address in lamports (1 SOL = 1,000,000,000 lamports).
timestampi64Unix timestamp when the payment announcement was created on-chain.
token_accountOption<Pubkey>For SPL token payments, the associated token account holding the tokens. None for native SOL payments.
token_mintOption<Pubkey>For SPL token payments, the mint address of the token. None for native SOL payments.
Methods
is_sol_paymentpub fn is_sol_payment(&self) -> boolReturns true if this is a native SOL payment (not an SPL token).
for payment in payments {
if payment.is_sol_payment() {
println!("Received {} SOL", payment.balance as f64 / 1e9);
} else {
println!("Received SPL token payment");
}
}is_token_paymentpub fn is_token_payment(&self) -> boolReturns true if this is an SPL token payment.
let token_payments: Vec<_> = payments
.iter()
.filter(|p| p.is_token_payment())
.collect();
println!("Found {} token payments", token_payments.len());sol_amountpub fn sol_amount(&self) -> f64Convenience method that returns the balance converted to SOL (from lamports).
for payment in payments {
println!("Payment: {} SOL", payment.sol_amount());
// Equivalent to: payment.balance as f64 / 1_000_000_000.0
}agepub fn age(&self) -> DurationReturns how long ago the payment was made.
use std::time::Duration;
for payment in payments {
let age = payment.age();
if age < Duration::from_secs(3600) {
println!("Recent payment: {} minutes ago", age.as_secs() / 60);
} else {
println!("Payment from {} hours ago", age.as_secs() / 3600);
}
}derive_keypairpub fn derive_keypair(&self, meta: &StealthMetaAddress) -> Result<StealthKeypair>Derives the spending keypair for this payment using your meta-address.
let meta = StealthMetaAddress::load_from_file("~/.onyx/keys.json")?;
for payment in payments {
// Derive the keypair to spend these funds
let keypair = payment.derive_keypair(&meta)?;
// Verify derivation is correct
assert_eq!(keypair.address(), payment.stealth_address);
// Get Solana keypair for signing
let solana_kp = keypair.to_solana_keypair()?;
}Usage with Scanner
StealthPayment objects are typically obtained from the Scanner:
use onyx_sdk::prelude::*;
let meta = StealthMetaAddress::load_from_file("~/.onyx/keys.json")?;
let scanner = Scanner::new(&meta);
// Fetch announcements from the on-chain registry
let announcements = fetch_announcements(&rpc_client)?;
// Scan returns Vec<StealthPayment>
let payments: Vec<StealthPayment> = scanner.scan(&announcements)?;
// Process each payment
for payment in payments {
println!("Found payment:");
println!(" Address: {}", payment.stealth_address);
println!(" Amount: {} SOL", payment.sol_amount());
println!(" Age: {:?}", payment.age());
if payment.is_token_payment() {
println!(" Token: {}", payment.token_mint.unwrap());
}
}Claiming Funds
Once you have a StealthPayment, you can claim the funds by deriving the keypair:
use onyx_sdk::prelude::*;
use solana_sdk::signature::Signer;
let meta = StealthMetaAddress::load_from_file("~/.onyx/keys.json")?;
let payments = scanner.scan(&announcements)?;
for payment in payments {
// Skip empty accounts
if payment.balance == 0 {
continue;
}
// Derive spending capability
let keypair = payment.derive_keypair(&meta)?;
let signer = keypair.to_solana_keypair()?;
// Build transfer instruction
let destination = Pubkey::from_str("your-main-wallet")?;
if payment.is_sol_payment() {
// Transfer SOL
let ix = system_instruction::transfer(
&payment.stealth_address,
&destination,
payment.balance,
);
// Sign and send
let tx = Transaction::new_signed_with_payer(
&[ix],
Some(&payment.stealth_address),
&[&signer],
recent_blockhash,
);
rpc_client.send_and_confirm_transaction(&tx)?;
} else {
// Transfer SPL tokens
// ... SPL token transfer logic
}
println!("Claimed {} SOL from {}",
payment.sol_amount(),
payment.stealth_address
);
}Serialization
StealthPayment implements Serialize, making it easy to store or transmit:
use serde_json;
// Serialize to JSON
let json = serde_json::to_string_pretty(&payment)?;
println!("{}", json);
// Output:
// {
// "stealth_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
// "ephemeral_pubkey": [123, 45, 67, ...],
// "balance": 1000000000,
// "timestamp": 1703116800,
// "token_account": null,
// "token_mint": null
// }