tycho-simulation 0.255.1

Provides tools for interacting with protocol states, calculating spot prices, and quoting token swaps.
Documentation
use num_bigint::BigInt;
use tracing::{debug, info};
use tycho_client::feed::synchronizer::ComponentWithState;

use crate::evm::protocol::vm::utils::json_deserialize_be_bigint_list;

/// Filters out pools that DCI currently fails to find some accounts for
pub fn balancer_v2_pool_filter(component: &ComponentWithState) -> bool {
    const UNSUPPORTED_COMPONENT_IDS: [&str; 6] = [
        "0x848a5564158d84b8a8fb68ab5d004fae11619a5400000000000000000000066a",
        "0x596192bb6e41802428ac943d2f1476c1af25cc0e000000000000000000000659",
        "0x05ff47afada98a98982113758878f9a8b9fdda0a000000000000000000000645",
        "0x265b6d1a6c12873a423c177eba6dd2470f40a3b50001000000000000000003fd",
        "0x9f9d900462492d4c21e9523ca95a7cd86142f298000200000000000000000462",
        "0x42ed016f826165c2e5976fe5bc3df540c5ad0af700000000000000000000058b",
    ];

    if UNSUPPORTED_COMPONENT_IDS.contains(
        &component
            .component
            .id
            .to_lowercase()
            .as_str(),
    ) {
        debug!(
            "Filtering out Balancer pools {} that have missing Accounts after DCI update.",
            component.component.id
        );
        return false;
    }

    true
}

/// Filters out uniswap v4 pools with non-Euler hooks
pub fn uniswap_v4_euler_hook_pool_filter(component: &ComponentWithState) -> bool {
    component
        .component
        .static_attributes
        .get("hook_identifier")
        .and_then(|bytes| std::str::from_utf8(bytes).ok())
        .is_some_and(|s| s == "euler_v1")
}

/// Filters out uniswap v4 pools with non-Angstrom hooks
pub fn uniswap_v4_angstrom_hook_pool_filter(component: &ComponentWithState) -> bool {
    component
        .component
        .static_attributes
        .get("hook_identifier")
        .and_then(|bytes| std::str::from_utf8(bytes).ok())
        .is_some_and(|s| s == "angstrom_v1")
}

/// Filters out pools that have unsupported token types in Curve
pub fn curve_pool_filter(component: &ComponentWithState) -> bool {
    if let Some(asset_types) = component
        .component
        .static_attributes
        .get("asset_types")
    {
        if json_deserialize_be_bigint_list(asset_types)
            .unwrap()
            .iter()
            .any(|t| t != &BigInt::ZERO)
        {
            debug!(
                "Filtering out Curve pool {} because it has unsupported token type",
                component.component.id
            );
            return false;
        }
    }

    if let Some(asset_type) = component
        .component
        .static_attributes
        .get("asset_type")
    {
        let types_str = std::str::from_utf8(asset_type).expect("Invalid UTF-8 data");
        if types_str != "0x00" {
            debug!(
                "Filtering out Curve pool {} because it has unsupported token type",
                component.component.id
            );
            return false;
        }
    }

    if let Some(stateless_addrs) = component
        .state
        .attributes
        .get("stateless_contract_addr_0")
    {
        let impl_str = std::str::from_utf8(stateless_addrs).expect("Invalid UTF-8 data");
        // Uses oracles
        if impl_str == "0x847ee1227a9900b73aeeb3a47fac92c52fd54ed9" {
            debug!(
                "Filtering out Curve pool {} because it has proxy implementation {}",
                component.component.id, impl_str
            );
            return false;
        }
    }
    if let Some(factory_attribute) = component
        .component
        .static_attributes
        .get("factory")
    {
        let factory = std::str::from_utf8(factory_attribute).expect("Invalid UTF-8 data");
        if factory.to_lowercase() == "0xf18056bbd320e96a48e3fbf8bc061322531aac99" {
            debug!(
                "Filtering out Curve pool {} because it belongs to an unsupported factory",
                component.component.id
            );
            return false;
        }
    };

    // Curve pools with rebasing tokens that are not supported
    const UNSUPPORTED_REBASING_COMPONENT_IDS: [&str; 2] = [
        "0xdc24316b9ae028f1497c275eb9192a3ea0f67022",
        "0x828b154032950c8ff7cf8085d841723db2696056",
    ];
    if UNSUPPORTED_REBASING_COMPONENT_IDS.contains(
        &component
            .component
            .id
            .to_lowercase()
            .as_str(),
    ) {
        debug!(
            "Filtering out Curve pool {} because it has a rebasing token that is not supported",
            component.component.id
        );
        return false;
    }

    true
}

/// Filters out pools that rely on ERC4626 in Balancer V3
pub fn balancer_v3_pool_filter(component: &ComponentWithState) -> bool {
    if let Some(erc4626) = component
        .component
        .static_attributes
        .get("erc4626")
    {
        if erc4626.to_vec() == [1u8] {
            info!(
                "Filtering out Balancer V3 pool {} because it uses ERC4626",
                component.component.id
            );
            return false;
        }
    }
    true
}

pub fn fluid_v1_paused_pools_filter(component: &ComponentWithState) -> bool {
    const PAUSED_POOLS: [&str; 4] = [
        // The components below are properly paused by substreams but the way indexer
        // handles tracing atm wrongly paused all components due to tracing failure. The
        // failure is unrelated to any issues with the protocol itself.
        "0x97479d9c09c7fd333bbfd07e93d4c8a669698ebc",
        "0xd0810e5cf08dcde266ecebef40cad806c7768d72",
        "0xf507a38aaf37339cc3beac4c7a58b17401bdf6bc",
        // The substreams did not detect this component as paused. It still reports
        // a high tvl value.
        "0x2886a01a0645390872a9eb99dae1283664b0c524",
    ];

    if PAUSED_POOLS.contains(
        &component
            .component
            .id
            .to_lowercase()
            .as_str(),
    ) {
        return false;
    }
    true
}

pub fn erc4626_filter(component: &ComponentWithState) -> bool {
    const UNSUPPORTED_POOLS: [&str; 4] = [
        "0x28B3a8fb53B741A8Fd78c0fb9A6B2393d896a43d",
        "0xe2e7a17dff93280dec073c995595155283e3c372",
        "0xfE6eb3b609a7C8352A241f7F3A21CEA4e9209B8f",
        "0x83f20f44975d03b1b09e64809b757c47f942beea",
    ];
    if UNSUPPORTED_POOLS.contains(
        &component
            .component
            .id
            .to_lowercase()
            .as_str(),
    ) {
        return false;
    }
    true
}