kabu_types_events/
swap_compose.rs

1use crate::Message;
2use crate::tx_compose::TxComposeData;
3use alloy_primitives::{Bytes, TxHash, U256};
4use alloy_rpc_types::TransactionRequest;
5use eyre::{Result, eyre};
6use kabu_types_blockchain::GethStateUpdateVec;
7use kabu_types_market::PoolId;
8use kabu_types_swap::Swap;
9use reth_ethereum_primitives::EthPrimitives;
10use reth_node_types::NodePrimitives;
11use revm::DatabaseRef;
12use std::ops::Deref;
13
14#[derive(Clone, Debug)]
15pub enum TxState<N: NodePrimitives = EthPrimitives> {
16    Stuffing(N::SignedTx),
17    SignatureRequired(Box<TransactionRequest>),
18    ReadyForBroadcast(Bytes),
19    ReadyForBroadcastStuffing(Bytes),
20}
21
22impl<N: NodePrimitives> TxState<N> {
23    pub fn rlp(&self) -> Result<Bytes> {
24        match self {
25            TxState::Stuffing(_t) => {
26                // TODO: Need to implement encoding for NodePrimitives::SignedTx
27                Err(eyre!("Encoding not yet implemented for NodePrimitives"))
28            }
29            TxState::ReadyForBroadcast(t) | TxState::ReadyForBroadcastStuffing(t) => Ok(t.clone()),
30            _ => Err(eyre!("NOT_READY_FOR_BROADCAST")),
31        }
32    }
33}
34
35#[derive(Clone, Debug)]
36pub enum SwapComposeMessage<DB, N: NodePrimitives = EthPrimitives> {
37    Prepare(SwapComposeData<DB, N>),
38    Estimate(SwapComposeData<DB, N>),
39    Ready(SwapComposeData<DB, N>),
40}
41
42impl<DB, N: NodePrimitives> Deref for SwapComposeMessage<DB, N> {
43    type Target = SwapComposeData<DB, N>;
44
45    fn deref(&self) -> &Self::Target {
46        self.data()
47    }
48}
49
50impl<DB, N: NodePrimitives> SwapComposeMessage<DB, N> {
51    pub fn data(&self) -> &SwapComposeData<DB, N> {
52        match self {
53            SwapComposeMessage::Prepare(x) | SwapComposeMessage::Estimate(x) | SwapComposeMessage::Ready(x) => x,
54        }
55    }
56}
57
58#[derive(Clone, Debug)]
59pub struct SwapComposeData<DB, N: NodePrimitives = EthPrimitives> {
60    pub tx_compose: TxComposeData<N>,
61    pub swap: Swap,
62    pub prestate: Option<DB>,
63    pub poststate: Option<DB>,
64    pub poststate_update: Option<GethStateUpdateVec>,
65    pub origin: Option<String>,
66    pub tips_pct: Option<u32>,
67    pub tips: Option<U256>,
68}
69
70impl<DB: Clone + 'static, N: NodePrimitives> SwapComposeData<DB, N> {
71    pub fn same_stuffing(&self, others_stuffing_txs_hashes: &[TxHash]) -> bool {
72        let tx_len = self.tx_compose.stuffing_txs_hashes.len();
73
74        if tx_len != others_stuffing_txs_hashes.len() {
75            false
76        } else if tx_len == 0 {
77            true
78        } else {
79            others_stuffing_txs_hashes.iter().all(|x| self.tx_compose.stuffing_txs_hashes.contains(x))
80        }
81    }
82
83    pub fn cross_pools(&self, others_pools: &[PoolId]) -> bool {
84        self.swap.get_pool_id_vec().iter().any(|x| others_pools.contains(x))
85    }
86
87    pub fn first_stuffing_hash(&self) -> TxHash {
88        self.tx_compose.stuffing_txs_hashes.first().map_or(TxHash::default(), |x| *x)
89    }
90
91    pub fn tips_gas_ratio(&self) -> U256 {
92        if self.tx_compose.gas == 0 { U256::ZERO } else { self.tips.unwrap_or_default() / U256::from(self.tx_compose.gas) }
93    }
94
95    pub fn profit_eth_gas_ratio(&self) -> U256 {
96        if self.tx_compose.gas == 0 { U256::ZERO } else { self.swap.arb_profit_eth() / U256::from(self.tx_compose.gas) }
97    }
98
99    pub fn gas_price(&self) -> u128 {
100        self.tx_compose.next_block_base_fee as u128 + self.tx_compose.priority_gas_fee as u128
101    }
102
103    pub fn gas_cost(&self) -> u128 {
104        self.tx_compose.gas as u128 * (self.tx_compose.next_block_base_fee as u128 + self.tx_compose.priority_gas_fee as u128)
105    }
106}
107
108impl<DB: DatabaseRef + Send + Sync + Clone + 'static, N: NodePrimitives> Default for SwapComposeData<DB, N> {
109    fn default() -> Self {
110        Self {
111            tx_compose: Default::default(),
112            swap: Swap::None,
113            prestate: None,
114            poststate: None,
115            poststate_update: None,
116            origin: None,
117            tips_pct: None,
118            tips: None,
119        }
120    }
121}
122
123pub type MessageSwapCompose<DB, N = EthPrimitives> = Message<SwapComposeMessage<DB, N>>;
124
125impl<DB, N: NodePrimitives> MessageSwapCompose<DB, N> {
126    pub fn prepare(data: SwapComposeData<DB, N>) -> Self {
127        Message::new(SwapComposeMessage::Prepare(data))
128    }
129
130    pub fn estimate(data: SwapComposeData<DB, N>) -> Self {
131        Message::new(SwapComposeMessage::Estimate(data))
132    }
133
134    pub fn ready(data: SwapComposeData<DB, N>) -> Self {
135        Message::new(SwapComposeMessage::Ready(data))
136    }
137}