Skip to main content

bulk_client/transaction/
signer.rs

1use eyre::bail;
2use solana_keypair::{keypair_from_seed, Keypair};
3use solana_pubkey::Pubkey;
4
5use solana_signature::Signature;
6use solana_signer::Signer;
7
8/// Ed25519 signer for Bulk exchange transactions.
9///
10/// # Example
11///
12/// ```text
13/// let signer = TransactionSigner::from_private_key("base58_key")?;
14/// let mut tx = Transaction { .. };
15/// tx.sign(&signer)?;
16/// ```
17#[derive(Debug)]
18#[allow(unused)]
19pub struct TransactionSigner {
20    keypair: Keypair,
21}
22
23#[allow(unused)]
24impl TransactionSigner {
25    /// Create a signer from a base58-encoded private key (32-byte seed).
26    ///
27    /// # Arguments
28    /// - `private_key`: 32 or 64 byte private key
29    pub fn from_private_key(key_b58: &str) -> eyre::Result<Self> {
30        let key_bytes = bs58::decode(key_b58).into_vec()?;
31
32        let keypair = if key_bytes.len() == 64 {
33            // Full 64-byte keypair (secret + public)
34            Keypair::try_from(key_bytes.as_slice())
35                .map_err(|e| eyre::eyre!("invalid 64-byte keypair: {e}"))?
36        } else if key_bytes.len() >= 32 {
37            // 32-byte seed — derive the keypair
38            keypair_from_seed(&key_bytes[..32])
39                .map_err(|e| eyre::eyre!("failed to create keypair from seed: {e}"))?
40        } else {
41            bail!(
42                "private key {} is wrong size (got {} bytes)",
43                key_b58,
44                key_bytes.len()
45            );
46        };
47
48        Ok(Self { keypair })
49    }
50
51    /// Sign an arbitrary byte slice and return the raw 64-byte signature.
52    ///
53    /// Used by [`BulkHttpClient`] for generic (non-`Signable`) payloads
54    /// such as leverage updates, agent wallet management, and faucet requests,
55    /// where the exchange expects a signature over the canonical JSON string.
56    pub fn sign_bytes(&self, message: &[u8]) -> Signature {
57        self.keypair.sign_message(message)
58    }
59
60    /// Get pubkey
61    pub fn public_key(&self) -> Pubkey {
62        self.keypair.pubkey()
63    }
64
65    /// Get pubkey as b58 encoding
66    pub fn public_key_b58(&self) -> String {
67        self.keypair.pubkey().to_string()
68    }
69}
70
71impl Clone for TransactionSigner {
72    fn clone(&self) -> Self {
73        Self {
74            keypair: self.keypair.insecure_clone(),
75        }
76    }
77}