openzeppelin_relayer/services/signer/stellar/
mod.rs

1// openzeppelin-relayer/src/services/signer/stellar/mod.rs
2//! Stellar signer implementation (local keystore)
3
4mod local_signer;
5mod vault_signer;
6
7use async_trait::async_trait;
8use local_signer::*;
9use vault_signer::*;
10
11use crate::{
12    domain::{SignDataRequest, SignDataResponse, SignTransactionResponse, SignTypedDataRequest},
13    models::{
14        Address, NetworkTransactionData, Signer as SignerDomainModel, SignerConfig,
15        SignerRepoModel, SignerType, TransactionRepoModel, VaultSignerConfig,
16    },
17    services::{
18        signer::{SignXdrTransactionResponseStellar, SignerError, SignerFactoryError},
19        Signer, VaultConfig, VaultService,
20    },
21};
22
23use super::DataSignerTrait;
24
25#[cfg(test)]
26use mockall::automock;
27
28#[cfg_attr(test, automock)]
29/// Trait defining Stellar-specific signing operations
30///
31/// This trait extends the basic signing functionality with methods specific
32/// to the Stellar blockchain, following the same pattern as SolanaSignTrait.
33#[async_trait]
34pub trait StellarSignTrait: Sync + Send {
35    /// Signs a Stellar transaction in XDR format
36    ///
37    /// # Arguments
38    ///
39    /// * `unsigned_xdr` - The unsigned transaction in XDR format
40    /// * `network_passphrase` - The network passphrase for the Stellar network
41    ///
42    /// # Returns
43    ///
44    /// A signed transaction response containing the signed XDR and signature
45    async fn sign_xdr_transaction(
46        &self,
47        unsigned_xdr: &str,
48        network_passphrase: &str,
49    ) -> Result<SignXdrTransactionResponseStellar, SignerError>;
50}
51
52pub enum StellarSigner {
53    Local(Box<LocalSigner>),
54    Vault(VaultSigner<VaultService>),
55}
56
57#[async_trait]
58impl Signer for StellarSigner {
59    async fn address(&self) -> Result<Address, SignerError> {
60        match self {
61            Self::Local(s) => s.address().await,
62            Self::Vault(s) => s.address().await,
63        }
64    }
65
66    async fn sign_transaction(
67        &self,
68        tx: NetworkTransactionData,
69    ) -> Result<SignTransactionResponse, SignerError> {
70        match self {
71            Self::Local(s) => s.sign_transaction(tx).await,
72            Self::Vault(s) => s.sign_transaction(tx).await,
73        }
74    }
75}
76
77#[async_trait]
78impl StellarSignTrait for StellarSigner {
79    async fn sign_xdr_transaction(
80        &self,
81        unsigned_xdr: &str,
82        network_passphrase: &str,
83    ) -> Result<SignXdrTransactionResponseStellar, SignerError> {
84        match self {
85            Self::Local(s) => {
86                s.sign_xdr_transaction(unsigned_xdr, network_passphrase)
87                    .await
88            }
89            Self::Vault(s) => {
90                s.sign_xdr_transaction(unsigned_xdr, network_passphrase)
91                    .await
92            }
93        }
94    }
95}
96
97pub struct StellarSignerFactory;
98
99impl StellarSignerFactory {
100    pub fn create_stellar_signer(
101        m: &SignerDomainModel,
102    ) -> Result<StellarSigner, SignerFactoryError> {
103        let signer = match &m.config {
104            SignerConfig::Local(_) => {
105                let local_signer = LocalSigner::new(m)?;
106                StellarSigner::Local(Box::new(local_signer))
107            }
108            SignerConfig::Vault(config) => {
109                let vault_config = VaultConfig::new(
110                    config.address.clone(),
111                    config.role_id.clone(),
112                    config.secret_id.clone(),
113                    config.namespace.clone(),
114                    config
115                        .mount_point
116                        .clone()
117                        .unwrap_or_else(|| "secret".to_string()),
118                    None,
119                );
120                let vault_service = VaultService::new(vault_config);
121
122                StellarSigner::Vault(VaultSigner::new(
123                    m.id.clone(),
124                    config.clone(),
125                    vault_service,
126                ))
127            }
128            SignerConfig::AwsKms(_) => {
129                return Err(SignerFactoryError::UnsupportedType("AWS KMS".into()))
130            }
131            SignerConfig::VaultTransit(_) => {
132                return Err(SignerFactoryError::UnsupportedType("Vault Transit".into()))
133            }
134            SignerConfig::Turnkey(_) => {
135                return Err(SignerFactoryError::UnsupportedType("Turnkey".into()))
136            }
137            SignerConfig::GoogleCloudKms(_) => {
138                return Err(SignerFactoryError::UnsupportedType(
139                    "Google Cloud KMS".into(),
140                ))
141            }
142        };
143        Ok(signer)
144    }
145}