StealthKeypair
A derived keypair for a specific stealth address. Used to sign transactions and claim funds from stealth payments.
Quick Overview
onyx_sdk::coreClone, ZeroizeSecurity Critical
StealthKeypair contains private key material. It implements Zeroize to securely clear memory when dropped. Never log, serialize, or persist these keypairs.
Definition
pub struct StealthKeypair {
/// The derived secret key for this stealth address
secret_key: SecretKey,
/// The corresponding public key (stealth address)
public_key: PublicKey,
}Note: Fields are private. Access the public key via address() and use to_solana_keypair() for signing.
Constructor Methods
derivepub fn derive(meta: &StealthMetaAddress, ephemeral_pubkey: &[u8; 32]) -> Result<Self>Derives the spending keypair for a stealth address using your meta-address and the sender's ephemeral public key.
use onyx_sdk::prelude::*;
let meta = StealthMetaAddress::load_from_file("~/.onyx/keys.json")?;
// From a scanned payment
let payment = payments.first().unwrap();
let keypair = StealthKeypair::derive(&meta, &payment.ephemeral_pubkey)?;
// Verify the derivation matches
assert_eq!(keypair.address(), payment.stealth_address);from_paymentpub fn from_payment(meta: &StealthMetaAddress, payment: &StealthPayment) -> Result<Self>Convenience method to derive a keypair directly from a StealthPayment.
// Equivalent to StealthKeypair::derive(&meta, &payment.ephemeral_pubkey)
let keypair = StealthKeypair::from_payment(&meta, &payment)?;Accessor Methods
addresspub fn address(&self) -> PubkeyReturns the Solana public key (address) for this keypair.
let keypair = StealthKeypair::derive(&meta, &ephemeral_pubkey)?;
let address = keypair.address();
println!("Stealth address: {}", address);
// Use for transaction building
let ix = system_instruction::transfer(
&address, // from (stealth address)
&destination, // to
amount,
);pubkey_bytespub fn pubkey_bytes(&self) -> [u8; 32]Returns the public key as raw bytes.
let bytes = keypair.pubkey_bytes();
println!("Public key bytes: {:?}", bytes);Conversion Methods
to_solana_keypairpub fn to_solana_keypair(&self) -> Result<solana_sdk::signature::Keypair>Converts to a Solana SDK Keypair for signing transactions.
use solana_sdk::signature::{Keypair, Signer};
let stealth_kp = StealthKeypair::derive(&meta, &ephemeral_pubkey)?;
let solana_kp: Keypair = stealth_kp.to_solana_keypair()?;
// Now use with Solana SDK
println!("Pubkey: {}", solana_kp.pubkey());
// Sign a transaction
let tx = Transaction::new_signed_with_payer(
&[instruction],
Some(&solana_kp.pubkey()),
&[&solana_kp],
recent_blockhash,
);to_bytespub fn to_bytes(&self) -> [u8; 64]Returns the keypair as 64 bytes (32 secret + 32 public). Handle with extreme care.
Danger: This exposes raw private key bytes. Only use when absolutely necessary, and ensure the bytes are securely erased after use.
Signing Transactions
The primary use of StealthKeypair is signing transactions to move funds:
use onyx_sdk::prelude::*;
use solana_sdk::{
signature::Signer,
system_instruction,
transaction::Transaction,
};
fn claim_payment(
meta: &StealthMetaAddress,
payment: &StealthPayment,
destination: &Pubkey,
rpc: &RpcClient,
) -> Result<Signature> {
// 1. Derive the keypair
let keypair = StealthKeypair::from_payment(meta, payment)?;
let signer = keypair.to_solana_keypair()?;
// 2. Build the transfer instruction
let transfer_ix = system_instruction::transfer(
&payment.stealth_address,
destination,
payment.balance,
);
// 3. Create and sign transaction
let recent_blockhash = rpc.get_latest_blockhash()?;
let tx = Transaction::new_signed_with_payer(
&[transfer_ix],
Some(&payment.stealth_address),
&[&signer],
recent_blockhash,
);
// 4. Send transaction
let signature = rpc.send_and_confirm_transaction(&tx)?;
Ok(signature)
}SPL Token Transfers
For SPL token payments, use the token program instructions:
use onyx_sdk::prelude::*;
use spl_token::instruction as token_instruction;
use spl_associated_token_account::get_associated_token_address;
fn claim_token_payment(
meta: &StealthMetaAddress,
payment: &StealthPayment,
destination_wallet: &Pubkey,
rpc: &RpcClient,
) -> Result<Signature> {
// Ensure this is a token payment
let token_mint = payment.token_mint
.ok_or(OnyxError::NotTokenPayment)?;
let source_token_account = payment.token_account
.ok_or(OnyxError::NotTokenPayment)?;
// Derive keypair
let keypair = StealthKeypair::from_payment(meta, payment)?;
let signer = keypair.to_solana_keypair()?;
// Get destination token account
let dest_token_account = get_associated_token_address(
destination_wallet,
&token_mint,
);
// Get token balance
let token_balance = rpc
.get_token_account_balance(&source_token_account)?
.amount
.parse::<u64>()?;
// Build transfer instruction
let transfer_ix = token_instruction::transfer(
&spl_token::id(),
&source_token_account,
&dest_token_account,
&payment.stealth_address,
&[],
token_balance,
)?;
// Sign and send
let tx = Transaction::new_signed_with_payer(
&[transfer_ix],
Some(&payment.stealth_address),
&[&signer],
rpc.get_latest_blockhash()?,
);
let signature = rpc.send_and_confirm_transaction(&tx)?;
Ok(signature)
}Memory Safety
StealthKeypair implements secure memory handling:
Private key bytes are securely zeroed when the keypair goes out of scope.
Cannot be serialized to prevent accidental persistence of private keys.
Debug trait does not expose private key material.
{
let keypair = StealthKeypair::derive(&meta, &ephemeral)?;
// Use the keypair
let tx = sign_transaction(&keypair)?;
} // keypair dropped here, private key memory is zeroed
// Attempting to use keypair here would be a compile error