API Reference/StealthPayment

StealthPayment

Represents a detected incoming payment. Returned by the Scanner when it finds payments addressed to your meta-address.

Quick Overview

Module:onyx_sdk::core
Traits:Clone, Debug, Serialize

Definition

struct
rust
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_addressPubkey

The 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.

balanceu64

Current balance of the stealth address in lamports (1 SOL = 1,000,000,000 lamports).

timestampi64

Unix 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_payment
pub fn is_sol_payment(&self) -> bool

Returns 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_payment
pub fn is_token_payment(&self) -> bool

Returns 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_amount
pub fn sol_amount(&self) -> f64

Convenience 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
}
age
pub fn age(&self) -> Duration

Returns 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_keypair
pub 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:

scanning_example.rs
rust
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:

claim_funds.rs
rust
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
// }