blueprint_evm_extra/extract/
contract.rs

1//! Contract Address Extractor.
2//!
3//! This simple extractor is used to extract the contract address from the current job call.
4//! This could be useful when you are using the [`MatchesContract`] filter.
5//!
6//! [`MatchesContract`]: crate::filters::contract::MatchesContract
7
8use alloy_primitives::Address;
9
10use blueprint_core::{
11    __composite_rejection as composite_rejection, __define_rejection as define_rejection,
12    __impl_deref as impl_deref, __impl_from as impl_from, FromJobCallParts,
13    job::call::Parts as JobCallParts,
14};
15
16/// Extracts the contract address from the current job call.
17#[derive(Debug, Clone, Copy)]
18pub struct ContractAddress(pub Address);
19
20impl ContractAddress {
21    /// The unique key used to store the contract address in the metadata.
22    pub const METADATA_KEY: &'static str = "X-EVM-CONTRACT-ADDRESS";
23}
24
25impl_deref!(ContractAddress: Address);
26impl_from!(Address, ContractAddress);
27
28define_rejection! {
29    #[body = "No contract address found in the metadata"]
30    /// This rejection is used to indicate that no contract address was found in the metadata.
31    pub struct MissingContractAddress;
32}
33
34define_rejection! {
35    #[body = "Contract address must be a valid address"]
36    /// This rejection is used to indicate that the contract address is not a valid address.
37    pub struct InvalidContractAddress;
38}
39
40composite_rejection! {
41    /// Rejection for contract address extractor
42    pub enum ContractAddressRejection {
43        MissingContractAddress,
44        InvalidContractAddress,
45    }
46}
47
48impl TryFrom<&mut JobCallParts> for ContractAddress {
49    type Error = ContractAddressRejection;
50
51    fn try_from(parts: &mut JobCallParts) -> Result<Self, Self::Error> {
52        let address = parts
53            .metadata
54            .get(Self::METADATA_KEY)
55            .ok_or(MissingContractAddress)?;
56        let address_bytes = address.as_bytes();
57        let address = Address::try_from(address_bytes).map_err(|_| InvalidContractAddress)?;
58        Ok(ContractAddress(address))
59    }
60}
61
62impl<Ctx> FromJobCallParts<Ctx> for ContractAddress
63where
64    Ctx: Send + Sync,
65{
66    type Rejection = ContractAddressRejection;
67    async fn from_job_call_parts(
68        parts: &mut JobCallParts,
69        _: &Ctx,
70    ) -> Result<Self, Self::Rejection> {
71        Self::try_from(parts)
72    }
73}