openzeppelin_relayer/services/signer/
mod.rs

1//! Signer service module for handling cryptographic operations across different blockchain
2//! networks.
3//!
4//! This module provides:
5//! - Common signer traits for different blockchain networks
6//! - Network-specific signer implementations (EVM, Solana, Stellar)
7//! - Factory methods for creating signers
8//! - Error handling for signing operations
9//!
10//! # Architecture
11//!
12//! ```text
13//! Signer Trait (Common Interface)
14//!   ├── EvmSigner
15//!   │   |── LocalSigner
16//!   |   |── TurnkeySigner
17//!   |   └── AwsKmsSigner
18//!   ├── SolanaSigner
19//!   │   |── LocalSigner
20//!   |   |── GoogleCloudKmsSigner
21//!   │   └── VaultTransitSigner
22//!   └── StellarSigner
23
24#![allow(unused_imports)]
25use async_trait::async_trait;
26use eyre::Result;
27#[cfg(test)]
28use mockall::automock;
29use serde::Serialize;
30use thiserror::Error;
31
32mod evm;
33pub use evm::*;
34
35mod solana;
36pub use solana::*;
37
38mod stellar;
39pub use stellar::*;
40
41use crate::{
42    domain::{SignDataRequest, SignDataResponse, SignTransactionResponse, SignTypedDataRequest},
43    models::{
44        Address, NetworkTransactionData, NetworkType, SignerError, SignerFactoryError,
45        SignerRepoModel, SignerType, TransactionError, TransactionRepoModel,
46    },
47};
48
49#[async_trait]
50#[cfg_attr(test, automock)]
51pub trait Signer: Send + Sync {
52    /// Returns the signer's ethereum address
53    async fn address(&self) -> Result<Address, SignerError>;
54
55    /// Signs a transaction
56    async fn sign_transaction(
57        &self,
58        transaction: NetworkTransactionData,
59    ) -> Result<SignTransactionResponse, SignerError>;
60}
61
62#[allow(dead_code)]
63#[allow(clippy::large_enum_variant)]
64pub enum NetworkSigner {
65    Evm(EvmSigner),
66    Solana(SolanaSigner),
67    Stellar(StellarSigner),
68}
69
70#[async_trait]
71impl Signer for NetworkSigner {
72    async fn address(&self) -> Result<Address, SignerError> {
73        match self {
74            Self::Evm(signer) => signer.address().await,
75            Self::Solana(signer) => signer.address().await,
76            Self::Stellar(signer) => signer.address().await,
77        }
78    }
79
80    async fn sign_transaction(
81        &self,
82        transaction: NetworkTransactionData,
83    ) -> Result<SignTransactionResponse, SignerError> {
84        match self {
85            Self::Evm(signer) => signer.sign_transaction(transaction).await,
86            Self::Solana(signer) => signer.sign_transaction(transaction).await,
87            Self::Stellar(signer) => signer.sign_transaction(transaction).await,
88        }
89    }
90}
91
92#[async_trait]
93impl DataSignerTrait for NetworkSigner {
94    async fn sign_data(&self, request: SignDataRequest) -> Result<SignDataResponse, SignerError> {
95        match self {
96            Self::Evm(signer) => {
97                let signature = signer
98                    .sign_data(request)
99                    .await
100                    .map_err(|e| SignerError::SigningError(e.to_string()))?;
101
102                Ok(signature)
103            }
104            Self::Solana(_) => Err(SignerError::UnsupportedTypeError(
105                "Solana: sign data not supported".into(),
106            )),
107            Self::Stellar(_) => Err(SignerError::UnsupportedTypeError(
108                "Stellar: sign data not supported".into(),
109            )),
110        }
111    }
112
113    async fn sign_typed_data(
114        &self,
115        request: SignTypedDataRequest,
116    ) -> Result<SignDataResponse, SignerError> {
117        match self {
118            Self::Evm(signer) => signer
119                .sign_typed_data(request)
120                .await
121                .map_err(|e| SignerError::SigningError(e.to_string())),
122            Self::Solana(_) => Err(SignerError::UnsupportedTypeError(
123                "Solana: Signing typed data not supported".into(),
124            )),
125            Self::Stellar(_) => Err(SignerError::UnsupportedTypeError(
126                "Stellar: Signing typed data not supported".into(),
127            )),
128        }
129    }
130}
131
132pub struct SignerFactory;
133
134impl SignerFactory {
135    pub async fn create_signer(
136        network_type: &NetworkType,
137        signer_model: &SignerRepoModel,
138    ) -> Result<NetworkSigner, SignerFactoryError> {
139        let signer = match network_type {
140            NetworkType::Evm => {
141                let evm_signer = EvmSignerFactory::create_evm_signer(signer_model.clone()).await?;
142                NetworkSigner::Evm(evm_signer)
143            }
144            NetworkType::Solana => {
145                let solana_signer = SolanaSignerFactory::create_solana_signer(signer_model)?;
146                NetworkSigner::Solana(solana_signer)
147            }
148            NetworkType::Stellar => {
149                let stellar_signer = StellarSignerFactory::create_stellar_signer(signer_model)?;
150                NetworkSigner::Stellar(stellar_signer)
151            }
152        };
153
154        Ok(signer)
155    }
156}