trident_sdk/evm/
chain_handler.rs1use alloy_contract::Error as ContractError;
2use alloy_primitives::{Address, U256};
3use alloy_provider::network::AnyNetwork;
4use alloy_provider::{DynProvider, PendingTransactionError, Provider};
5use alloy_signer::Signer;
6use async_trait::async_trait;
7
8use crate::chain_handler::{
9 ChainHandler, ChainHandlerBuildError, ChainHandlerBuilder, ChainHandlerError,
10};
11use crate::conversions::ProtoConversionError;
12use crate::deposit::DepositContext;
13use crate::proto::v1;
14use crate::spend_attestation::SpendAttestationChainContext;
15use crate::{Domain, TridentClientBuilder};
16
17use super::signing;
18
19#[derive(Debug, thiserror::Error)]
24pub enum EvmChainError {
25 #[error("Contract call failed: {0}")]
27 Contract(#[from] ContractError),
28
29 #[error("Transaction pending error: {0}")]
31 PendingTransaction(#[from] PendingTransactionError),
32
33 #[error("Failed to sign spend intent: {0}")]
35 Signer(alloy_signer::Error),
36
37 #[error("Invalid proto conversion: {0}")]
39 ProtoConversion(#[from] ProtoConversionError),
40}
41
42pub(crate) struct EvmChainHandler {
43 provider: DynProvider<AnyNetwork>,
44 signer: Box<dyn Signer + Send + Sync>,
45 deposit_contract: Address,
46 delivery_contract: Address,
47}
48
49impl EvmChainHandler {
50 pub(crate) fn new(
51 provider: DynProvider<AnyNetwork>,
52 signer: Box<dyn Signer + Send + Sync>,
53 deposit_contract: Address,
54 delivery_contract: Address,
55 ) -> Self {
56 Self {
57 provider,
58 signer,
59 deposit_contract,
60 delivery_contract,
61 }
62 }
63}
64
65#[async_trait]
66impl ChainHandler for EvmChainHandler {
67 fn delivery_contract(&self) -> v1::MultiChainAddress {
68 self.delivery_contract.into()
69 }
70
71 fn deposit_contract(&self) -> v1::MultiChainAddress {
72 self.deposit_contract.into()
73 }
74
75 fn signer(&self) -> v1::MultiChainAddress {
76 self.signer.address().into()
77 }
78
79 async fn sign_spend_intent(
80 &self,
81 intent: v1::SpendIntent,
82 ) -> Result<Vec<u8>, ChainHandlerError> {
83 signing::sign_spend_intent(self.signer.as_ref(), intent)
84 .await
85 .map_err(Into::into)
86 }
87
88 fn prepare_deposit(
89 &self,
90 token: v1::MultiChainAddress,
91 amount: U256,
92 ) -> Result<DepositContext, ChainHandlerError> {
93 let token_address = Address::try_from(token).map_err(EvmChainError::from)?;
94 Ok(DepositContext::Evm {
95 provider: self.provider.clone(),
96 signer_address: self.signer.address(),
97 deposit_contract: self.deposit_contract,
98 token: token_address,
99 amount,
100 })
101 }
102
103 fn prepare_spend_attestation(&self) -> SpendAttestationChainContext {
104 SpendAttestationChainContext::Evm {
105 provider: self.provider.clone(),
106 delivery_contract: self.delivery_contract,
107 signer_address: self.signer.address(),
108 }
109 }
110}
111
112pub(crate) struct EvmChainHandlerBuilder {
116 provider: DynProvider<AnyNetwork>,
117 signer: Box<dyn Signer + Send + Sync>,
118}
119
120#[async_trait]
121impl ChainHandlerBuilder for EvmChainHandlerBuilder {
122 async fn build(
123 self: Box<Self>,
124 delivery_contract: v1::MultiChainAddress,
125 deposit_contract: v1::MultiChainAddress,
126 ) -> Result<Box<dyn ChainHandler>, ChainHandlerBuildError> {
127 let delivery_contract = Address::try_from(delivery_contract)?;
128 let deposit_contract = Address::try_from(deposit_contract)?;
129 Ok(Box::new(EvmChainHandler::new(
130 self.provider,
131 self.signer,
132 deposit_contract,
133 delivery_contract,
134 )))
135 }
136}
137
138impl TridentClientBuilder {
139 pub fn with_evm_chain(
145 self,
146 domain: Domain,
147 provider: impl Provider<AnyNetwork> + 'static,
148 signer: impl Signer + Send + Sync + 'static,
149 ) -> Self {
150 self.with_chain(
151 domain,
152 EvmChainHandlerBuilder {
153 provider: provider.erased(),
154 signer: Box::new(signer),
155 },
156 )
157 }
158}