nautilus_blockchain/hypersync/
transform.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use alloy::primitives::U256;
17use hypersync_client::format::Hex;
18use nautilus_core::{UnixNanos, datetime::NANOSECONDS_IN_SECOND};
19use nautilus_model::defi::{Block, Blockchain, hex::from_str_hex_to_u64};
20use ustr::Ustr;
21
22/// Converts a HyperSync block format to our internal [`Block`] type.
23///
24/// # Errors
25///
26/// Returns an error if required block fields are missing or if hex parsing fails.
27pub fn transform_hypersync_block(
28    chain: Blockchain,
29    received_block: hypersync_client::simple_types::Block,
30) -> Result<Block, anyhow::Error> {
31    let number = received_block
32        .number
33        .ok_or_else(|| anyhow::anyhow!("Missing block number"))?;
34    let gas_limit = from_str_hex_to_u64(
35        received_block
36            .gas_limit
37            .ok_or_else(|| anyhow::anyhow!("Missing gas limit"))?
38            .encode_hex()
39            .as_str(),
40    )?;
41    let gas_used = from_str_hex_to_u64(
42        received_block
43            .gas_used
44            .ok_or_else(|| anyhow::anyhow!("Missing gas used"))?
45            .encode_hex()
46            .as_str(),
47    )?;
48    let timestamp = from_str_hex_to_u64(
49        received_block
50            .timestamp
51            .ok_or_else(|| anyhow::anyhow!("Missing timestamp"))?
52            .encode_hex()
53            .as_str(),
54    )?;
55
56    let mut block = Block::new(
57        received_block
58            .hash
59            .ok_or_else(|| anyhow::anyhow!("Missing hash"))?
60            .to_string(),
61        received_block
62            .parent_hash
63            .ok_or_else(|| anyhow::anyhow!("Missing parent hash"))?
64            .to_string(),
65        number,
66        Ustr::from(
67            received_block
68                .miner
69                .ok_or_else(|| anyhow::anyhow!("Missing miner"))?
70                .to_string()
71                .as_str(),
72        ),
73        gas_limit,
74        gas_used,
75        UnixNanos::new(timestamp * NANOSECONDS_IN_SECOND),
76        Some(chain),
77    );
78
79    if let Some(base_fee_hex) = received_block.base_fee_per_gas {
80        let s = base_fee_hex.encode_hex();
81        let val = U256::from_str_radix(s.trim_start_matches("0x"), 16)?;
82        block = block.with_base_fee(val);
83    }
84
85    if let (Some(used_hex), Some(excess_hex)) =
86        (received_block.blob_gas_used, received_block.excess_blob_gas)
87    {
88        let used = U256::from_str_radix(used_hex.encode_hex().trim_start_matches("0x"), 16)?;
89        let excess = U256::from_str_radix(excess_hex.encode_hex().trim_start_matches("0x"), 16)?;
90        block = block.with_blob_gas(used, excess);
91    }
92
93    // TODO: HyperSync does not yet publush L1 gas metadata fields
94    // if let (Some(price_hex), Some(l1_used_hex), Some(scalar_hex)) = (
95    //     received_block.l1_gas_price,
96    //     received_block.l1_gas_used,
97    //     received_block.l1_fee_scalar,
98    // ) {
99    //     let price = U256::from_str_radix(price_hex.encode_hex().trim_start_matches("0x"), 16)?;
100    //     let used = from_str_hex_to_u64(l1_used_hex.encode_hex().as_str())?;
101    //     let scalar = from_str_hex_to_u64(scalar_hex.encode_hex().as_str())?;
102    //     block = block.with_l1_fee_components(price, used, scalar);
103    // }
104
105    Ok(block)
106}
107
108////////////////////////////////////////////////////////////////////////////////
109// Tests
110////////////////////////////////////////////////////////////////////////////////
111
112#[cfg(test)]
113mod tests {}