openzeppelin_relayer/services/signer/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! Signer service module for handling cryptographic operations across different blockchain
//! networks.
//!
//! This module provides:
//! - Common signer traits for different blockchain networks
//! - Network-specific signer implementations (EVM, Solana, Stellar)
//! - Factory methods for creating signers
//! - Error handling for signing operations
//!
//! # Architecture
//!
//! ```text
//! Signer Trait (Common Interface)
//!   ├── EvmSigner
//!   │   └── LocalSigner
//!   ├── SolanaSigner
//!   │   └── LocalSigner
//!   │   └── VaultTransitSigner
//!   └── StellarSigner

#![allow(unused_imports)]
use async_trait::async_trait;
use eyre::Result;
#[cfg(test)]
use mockall::automock;
use serde::Serialize;
use thiserror::Error;

mod evm;
pub use evm::*;

mod solana;
pub use solana::*;

mod stellar;
pub use stellar::*;

use crate::{
    domain::{SignDataRequest, SignDataResponse, SignTransactionResponse, SignTypedDataRequest},
    models::{
        Address, NetworkTransactionData, NetworkType, SignerError, SignerFactoryError,
        SignerRepoModel, SignerType, TransactionError, TransactionRepoModel,
    },
};

#[async_trait]
#[cfg_attr(test, automock)]
pub trait Signer: Send + Sync {
    /// Returns the signer's ethereum address
    async fn address(&self) -> Result<Address, SignerError>;

    /// Signs a transaction
    async fn sign_transaction(
        &self,
        transaction: NetworkTransactionData,
    ) -> Result<SignTransactionResponse, SignerError>;
}

#[allow(dead_code)]
pub enum NetworkSigner {
    Evm(EvmSigner),
    Solana(SolanaSigner),
    Stellar(EvmSigner), // TODO replace with StellarSigner
}

#[async_trait]
impl Signer for NetworkSigner {
    async fn address(&self) -> Result<Address, SignerError> {
        match self {
            Self::Evm(signer) => signer.address().await,
            Self::Solana(signer) => signer.address().await,
            Self::Stellar(signer) => signer.address().await,
        }
    }

    async fn sign_transaction(
        &self,
        transaction: NetworkTransactionData,
    ) -> Result<SignTransactionResponse, SignerError> {
        match self {
            Self::Evm(signer) => signer.sign_transaction(transaction).await,
            Self::Solana(signer) => signer.sign_transaction(transaction).await,
            Self::Stellar(signer) => signer.sign_transaction(transaction).await,
        }
    }
}

#[async_trait]
impl DataSignerTrait for NetworkSigner {
    async fn sign_data(&self, request: SignDataRequest) -> Result<SignDataResponse, SignerError> {
        match self {
            Self::Evm(signer) => {
                let signature = signer
                    .sign_data(request)
                    .await
                    .map_err(|e| SignerError::SigningError(e.to_string()))?;

                Ok(signature)
            }
            Self::Solana(_) => Err(SignerError::UnsupportedTypeError(
                "Solana: sign data not supported".into(),
            )),
            Self::Stellar(_) => Err(SignerError::UnsupportedTypeError(
                "Stellar: sign data not supported".into(),
            )),
        }
    }

    async fn sign_typed_data(
        &self,
        request: SignTypedDataRequest,
    ) -> Result<SignDataResponse, SignerError> {
        match self {
            Self::Evm(signer) => signer
                .sign_typed_data(request)
                .await
                .map_err(|e| SignerError::SigningError(e.to_string())),
            Self::Solana(_) => Err(SignerError::UnsupportedTypeError(
                "Solana: Signing typed data not supported".into(),
            )),
            Self::Stellar(_) => Err(SignerError::UnsupportedTypeError(
                "Stellar: Signing typed data not supported".into(),
            )),
        }
    }
}

pub struct SignerFactory;

impl SignerFactory {
    pub fn create_signer(
        network_type: &NetworkType,
        signer_model: &SignerRepoModel,
    ) -> Result<NetworkSigner, SignerFactoryError> {
        let signer = match network_type {
            NetworkType::Evm => {
                let evm_signer = EvmSignerFactory::create_evm_signer(signer_model)?;
                NetworkSigner::Evm(evm_signer)
            }
            NetworkType::Solana => {
                let solana_signer = SolanaSignerFactory::create_solana_signer(signer_model)?;
                NetworkSigner::Solana(solana_signer)
            }
            NetworkType::Stellar => {
                return Err(SignerFactoryError::UnsupportedType("Vault".into()));
            }
        };

        Ok(signer)
    }
}