openzeppelin_relayer/services/signer/
mod.rs1#![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::{
43 SignDataRequest, SignDataResponse, SignTransactionResponse, SignTypedDataRequest,
44 SignXdrTransactionResponseStellar,
45 },
46 models::{
47 Address, DecoratedSignature, NetworkTransactionData, NetworkType,
48 Signer as SignerDomainModel, SignerError, SignerFactoryError, SignerType, TransactionError,
49 TransactionRepoModel,
50 },
51};
52
53#[derive(Debug, Clone, Serialize)]
55pub struct XdrSigningResponse {
56 pub signed_xdr: String,
58 pub signature: DecoratedSignature,
60}
61
62#[async_trait]
63#[cfg_attr(test, automock)]
64pub trait Signer: Send + Sync {
65 async fn address(&self) -> Result<Address, SignerError>;
67
68 async fn sign_transaction(
70 &self,
71 transaction: NetworkTransactionData,
72 ) -> Result<SignTransactionResponse, SignerError>;
73}
74
75#[allow(dead_code)]
76#[allow(clippy::large_enum_variant)]
77pub enum NetworkSigner {
78 Evm(EvmSigner),
79 Solana(SolanaSigner),
80 Stellar(StellarSigner),
81}
82
83#[async_trait]
84impl Signer for NetworkSigner {
85 async fn address(&self) -> Result<Address, SignerError> {
86 match self {
87 Self::Evm(signer) => signer.address().await,
88 Self::Solana(signer) => signer.address().await,
89 Self::Stellar(signer) => signer.address().await,
90 }
91 }
92
93 async fn sign_transaction(
94 &self,
95 transaction: NetworkTransactionData,
96 ) -> Result<SignTransactionResponse, SignerError> {
97 match self {
98 Self::Evm(signer) => signer.sign_transaction(transaction).await,
99 Self::Solana(signer) => signer.sign_transaction(transaction).await,
100 Self::Stellar(signer) => signer.sign_transaction(transaction).await,
101 }
102 }
103}
104
105#[async_trait]
106impl DataSignerTrait for NetworkSigner {
107 async fn sign_data(&self, request: SignDataRequest) -> Result<SignDataResponse, SignerError> {
108 match self {
109 Self::Evm(signer) => {
110 let signature = signer
111 .sign_data(request)
112 .await
113 .map_err(|e| SignerError::SigningError(e.to_string()))?;
114
115 Ok(signature)
116 }
117 Self::Solana(_) => Err(SignerError::UnsupportedTypeError(
118 "Solana: sign data not supported".into(),
119 )),
120 Self::Stellar(_) => Err(SignerError::UnsupportedTypeError(
121 "Stellar: sign data not supported".into(),
122 )),
123 }
124 }
125
126 async fn sign_typed_data(
127 &self,
128 request: SignTypedDataRequest,
129 ) -> Result<SignDataResponse, SignerError> {
130 match self {
131 Self::Evm(signer) => signer
132 .sign_typed_data(request)
133 .await
134 .map_err(|e| SignerError::SigningError(e.to_string())),
135 Self::Solana(_) => Err(SignerError::UnsupportedTypeError(
136 "Solana: Signing typed data not supported".into(),
137 )),
138 Self::Stellar(_) => Err(SignerError::UnsupportedTypeError(
139 "Stellar: Signing typed data not supported".into(),
140 )),
141 }
142 }
143}
144
145pub struct SignerFactory;
146
147impl SignerFactory {
148 pub async fn create_signer(
149 network_type: &NetworkType,
150 signer_model: &SignerDomainModel,
151 ) -> Result<NetworkSigner, SignerFactoryError> {
152 let signer = match network_type {
153 NetworkType::Evm => {
154 let evm_signer = EvmSignerFactory::create_evm_signer(signer_model.clone()).await?;
155 NetworkSigner::Evm(evm_signer)
156 }
157 NetworkType::Solana => {
158 let solana_signer = SolanaSignerFactory::create_solana_signer(signer_model)?;
159 NetworkSigner::Solana(solana_signer)
160 }
161 NetworkType::Stellar => {
162 let stellar_signer = StellarSignerFactory::create_stellar_signer(signer_model)?;
163 NetworkSigner::Stellar(stellar_signer)
164 }
165 };
166
167 Ok(signer)
168 }
169}