kabu_execution_multicaller/
swapline_encoder.rs

1use std::sync::Arc;
2
3use alloy_primitives::{Address, U256};
4use eyre::{eyre, Result};
5use tracing::trace;
6
7use crate::pool_abi_encoder::ProtocolAbiSwapEncoderTrait;
8use crate::pool_opcodes_encoder::{MulticallerOpcodesPayload, ProtocolSwapOpcodesEncoderV2, SwapOpcodesEncoderTrait};
9use crate::ProtocolABIEncoderV2;
10use kabu_defi_abi::AbiEncoderHelper;
11use kabu_defi_address_book::TokenAddressEth;
12use kabu_types_blockchain::{MulticallerCall, MulticallerCalls};
13use kabu_types_entities::SwapAmountType::RelativeStack;
14use kabu_types_entities::{PoolWrapper, SwapAmountType, SwapLine, Token};
15
16#[derive(Clone)]
17pub struct SwapLineEncoder {
18    pub multicaller_address: Address,
19    abi_encoder: Arc<dyn ProtocolAbiSwapEncoderTrait>,
20    opcodes_encoder: Arc<dyn SwapOpcodesEncoderTrait>,
21}
22
23impl SwapLineEncoder {
24    pub fn new(
25        multicaller_address: Address,
26        abi_encoder: Arc<dyn ProtocolAbiSwapEncoderTrait>,
27        opcodes_encoder: Arc<dyn SwapOpcodesEncoderTrait>,
28    ) -> SwapLineEncoder {
29        SwapLineEncoder { multicaller_address, abi_encoder, opcodes_encoder }
30    }
31
32    pub fn default_with_address(multicaller_address: Address) -> SwapLineEncoder {
33        let abi_encoder = Arc::new(ProtocolABIEncoderV2::default());
34        let opcodes_encoder = Arc::new(ProtocolSwapOpcodesEncoderV2::default());
35
36        SwapLineEncoder { multicaller_address, abi_encoder, opcodes_encoder }
37    }
38
39    pub fn encode_flash_swap_line_in_amount(
40        &self,
41        swap_path: &SwapLine,
42        inside_swap_opcodes: MulticallerCalls,
43        funds_to: Option<&PoolWrapper>,
44    ) -> Result<MulticallerCalls> {
45        trace!("encode_flash_swap_line_in_amount funds_to={:?}", funds_to);
46        let mut flash_swap_opcodes = MulticallerCalls::new();
47        let mut inside_opcodes = inside_swap_opcodes.clone();
48
49        let mut reverse_pools: Vec<PoolWrapper> = swap_path.pools().clone();
50        reverse_pools.reverse();
51        let mut reverse_tokens: Vec<Arc<Token>> = swap_path.tokens().clone();
52        reverse_tokens.reverse();
53
54        let mut prev_pool: Option<&PoolWrapper> = funds_to;
55
56        for (pool_idx, flash_pool) in reverse_pools.iter().enumerate() {
57            let token_from_address = reverse_tokens[pool_idx + 1].get_address();
58            let token_to_address = reverse_tokens[pool_idx].get_address();
59
60            let amount_in = if pool_idx == swap_path.pools().len() - 1 { swap_path.amount_in } else { SwapAmountType::RelativeStack(0) };
61
62            self.opcodes_encoder.encode_flash_swap_in_amount_provided(
63                &mut flash_swap_opcodes,
64                self.abi_encoder.as_ref(),
65                token_from_address,
66                token_to_address,
67                amount_in,
68                flash_pool.as_ref(),
69                prev_pool.map(|v| v.as_ref()),
70                MulticallerOpcodesPayload::Opcodes(inside_opcodes),
71                self.multicaller_address,
72            )?;
73
74            prev_pool = Some(flash_pool);
75            inside_opcodes = flash_swap_opcodes.clone();
76        }
77
78        Ok(flash_swap_opcodes)
79    }
80
81    pub fn encode_flash_swap_line_out_amount(
82        &self,
83        swap_path: &SwapLine,
84        inside_swap_opcodes: MulticallerCalls,
85    ) -> Result<MulticallerCalls> {
86        trace!("encode_flash_swap_line_out_amount inside_opcodes={}", inside_swap_opcodes.len());
87        let mut flash_swap_opcodes = MulticallerCalls::new();
88        let mut inside_opcodes = inside_swap_opcodes.clone();
89
90        let pools: Vec<PoolWrapper> = swap_path.pools().clone();
91
92        let tokens: Vec<Arc<Token>> = swap_path.tokens().clone();
93
94        for (pool_idx, flash_pool) in pools.iter().enumerate() {
95            flash_swap_opcodes = MulticallerCalls::new();
96
97            let token_from_address = tokens[pool_idx].get_address();
98            let token_to_address = tokens[pool_idx + 1].get_address();
99
100            let next_pool = if pool_idx < pools.len() - 1 { Some(&pools[pool_idx + 1]) } else { None };
101
102            let amount_out = if pool_idx == pools.len() - 1 { swap_path.amount_out } else { SwapAmountType::RelativeStack(0) };
103
104            self.opcodes_encoder.encode_flash_swap_out_amount_provided(
105                &mut flash_swap_opcodes,
106                self.abi_encoder.as_ref(),
107                token_from_address,
108                token_to_address,
109                amount_out,
110                flash_pool.as_ref(),
111                next_pool.map(|v| v.as_ref()),
112                MulticallerOpcodesPayload::Opcodes(inside_opcodes),
113                self.multicaller_address,
114            )?;
115
116            inside_opcodes = flash_swap_opcodes.clone();
117
118            /*let swap_to = match next_pool {
119                Some(next_pool) => next_pool.get_address(),
120                None => self.multicaller_address,
121            };
122
123            match flash_pool.get_class() {
124                PoolClass::UniswapV2 => {
125                    let mut get_in_amount_opcode =
126                        MulticallerCall::new_internal_call(&AbiEncoderHelper::encode_multicaller_uni2_get_in_amount(
127                            token_from_address,
128                            token_to_address,
129                            flash_pool.get_address(),
130                            amount_out.unwrap_or_default(),
131                            flash_pool.get_fee(),
132                        ));
133
134                    if amount_out.is_not_set() {
135                        get_in_amount_opcode.set_call_stack(false, 0, 0x24, 0x20);
136                    }
137
138                    inside_opcodes.insert(get_in_amount_opcode);
139
140                    if pool_idx == 0 && swap_to != flash_pool.get_address() {
141                        trace!(
142                            "retflash transfer token={:?}, to={:?}, amount=stack_no_rel_1",
143                            token_from_address,
144                            flash_pool.get_address()
145                        );
146
147                        let mut transfer_opcode = MulticallerCall::new_call(
148                            token_from_address,
149                            &AbiEncoderHelper::encode_erc20_transfer(flash_pool.get_address(), U256::ZERO),
150                        );
151                        transfer_opcode.set_call_stack(false, 1, 0x24, 0x20);
152                        inside_opcodes.add(transfer_opcode);
153                    };
154
155                    if swap_to != self.multicaller_address {
156                        trace!("retflash transfer token={:?}, to={:?}, amount=stack_norel_0", token_to_address, swap_to);
157
158                        let mut transfer_opcode =
159                            MulticallerCall::new_call(token_to_address, &AbiEncoderHelper::encode_erc20_transfer(swap_to, U256::ZERO));
160                        transfer_opcode.set_call_stack(false, 0, 0x24, 0x20);
161                        inside_opcodes.add(transfer_opcode);
162                    }
163                }
164                PoolClass::UniswapV3 | PoolClass::Maverick | PoolClass::PancakeV3 => {
165                    if pool_idx == 0 {
166                        trace!("retflash transfer token={:?}, to={:?}, amount=stack_norel_1", token_from_address, flash_pool.get_address());
167                        let mut transfer_opcode = MulticallerCall::new_call(
168                            token_from_address,
169                            &AbiEncoderHelper::encode_erc20_transfer(flash_pool.get_address(), U256::ZERO),
170                        );
171                        transfer_opcode.set_call_stack(false, 1, 0x24, 0x20);
172
173                        inside_opcodes.add(transfer_opcode);
174                    }
175                }
176
177                _ => {
178                    return Err(eyre!("CANNOT_ENCODE_FLASH_CALL"));
179                }
180            }
181
182            let inside_call_bytes = OpcodesEncoderV2::pack_do_calls_data(&inside_opcodes)?;
183            flash_swap_opcodes = MulticallerCalls::new();
184
185            trace!("flash swap_to {:?}", swap_to);
186
187
188             */
189            /*match flash_pool.get_class() {
190                PoolClass::UniswapV2 => {
191                    trace!(
192                        "uniswap v2 swap out amount provided for pool={:?}, amount_out={:?} receiver={} inside_opcodes_len={}",
193                        flash_pool.get_address(),
194                        amount_out,
195                        self.multicaller_address,
196                        inside_opcodes.len()
197                    );
198                    let mut swap_opcode = MulticallerCall::new_call(
199                        flash_pool.get_address(),
200                        &self.abi_encoder.encode_swap_out_amount_provided(
201                            flash_pool.as_ref(),
202                            token_from_address,
203                            token_to_address,
204                            amount_out.unwrap_or_default(),
205                            self.multicaller_address,
206                            inside_call_bytes,
207                        )?,
208                    );
209
210                    if amount_out.is_not_set() {
211                        trace!("uniswap v2 amount not set");
212                        swap_opcode.set_call_stack(
213                            true,
214                            0,
215                            self.abi_encoder.swap_out_amount_offset(flash_pool.as_ref(), token_from_address, token_to_address).unwrap(),
216                            0x20,
217                        );
218                    }
219
220                    flash_swap_opcodes.add(swap_opcode);
221
222                    inside_opcodes = flash_swap_opcodes.clone();
223                }
224                PoolClass::UniswapV3 | PoolClass::PancakeV3 | PoolClass::Maverick => {
225                    trace!(
226                        "uniswap v3 swap out amount provided for pool={:?}, amount_out={:?} receiver={} inside_opcodes_len={}",
227                        flash_pool.get_address(),
228                        amount_out,
229                        swap_to,
230                        inside_opcodes.len()
231                    );
232                    let mut swap_opcode = MulticallerCall::new_call(
233                        flash_pool.get_address(),
234                        &self.abi_encoder.encode_swap_out_amount_provided(
235                            flash_pool.as_ref(),
236                            token_from_address,
237                            token_to_address,
238                            amount_out.unwrap_or_default(),
239                            swap_to,
240                            inside_call_bytes,
241                        )?,
242                    );
243
244                    if amount_out.is_not_set() {
245                        trace!("uniswap v3 swap out amount is not set");
246
247                        flash_swap_opcodes.add(MulticallerCall::new_calculation_call(&Bytes::from(vec![0x8, 0x2A, 0x00])));
248
249                        swap_opcode.set_call_stack(
250                            true,
251                            0,
252                            self.abi_encoder.swap_out_amount_offset(flash_pool.as_ref(), token_from_address, token_to_address).unwrap(),
253                            0x20,
254                        );
255                    };
256
257                    flash_swap_opcodes.add(swap_opcode);
258
259                    inside_opcodes = flash_swap_opcodes.clone();
260                }
261                _ => {
262                    return Err(eyre!("CANNOT_ENCODE_FLASH_CALL"));
263                }
264            }
265
266             */
267        }
268
269        Ok(flash_swap_opcodes)
270    }
271
272    pub fn encode_flash_swap_dydx(&self, _inside_swap_opcodes: MulticallerCalls, _funds_from: Address) -> Result<MulticallerCalls> {
273        Err(eyre!("NOT_IMPLEMENTED"))
274    }
275
276    pub fn encode_swap_line_in_amount(&self, swap_path: &SwapLine, funds_to: Option<&PoolWrapper>) -> Result<MulticallerCalls> {
277        let mut swap_opcodes = MulticallerCalls::new();
278
279        let mut amount_in = swap_path.amount_in;
280
281        for i in 0..swap_path.pools().len() {
282            let token_from_address = swap_path.tokens()[i].get_address();
283            let token_to_address = swap_path.tokens()[i + 1].get_address();
284
285            let cur_pool = &swap_path.pools()[i].clone();
286            let next_pool: Option<&PoolWrapper> = if i < swap_path.pools().len() - 1 { Some(&swap_path.pools()[i + 1]) } else { funds_to };
287
288            trace!(
289                "encode_swap_line_in_amount for from={} to={} pool={}, next_pool={:?} funds_to {:?}",
290                token_from_address,
291                token_to_address,
292                cur_pool.get_address(),
293                next_pool.map(|next_pool| next_pool.get_address()),
294                funds_to
295            );
296
297            /*let amount_in = if i == 0 {
298                /*if let PreswapRequirement::Transfer(funds_needed_at) = self.abi_encoder.preswap_requirement(cur_pool.as_ref()) {
299                    if funds_needed_at != funds_from {
300                        trace!(
301                            "encode_swap_line_in_amount  i == 0  amount in {:?} funds {}->{}",
302                            swap_path.amount_in,
303                            funds_from,
304                            funds_needed_at
305                        );
306                        match swap_path.amount_in {
307                            SwapAmountType::Set(value) => {
308                                trace!("transfer token={:?}, to={:?}, amount={}", token_from_address, funds_needed_at, value);
309                                let transfer_opcode = MulticallerCall::new_call(
310                                    token_from_address,
311                                    &AbiEncoderHelper::encode_erc20_transfer(funds_needed_at, value),
312                                );
313                                swap_opcodes.add(transfer_opcode);
314                                swap_path.amount_in
315                            }
316                            SwapAmountType::Balance(addr) => {
317                                trace!("encode_swap_line_in_amount  i == 0 balance of addr={:?}", addr);
318                                let mut balance_opcode =
319                                    MulticallerCall::new_static_call(token_from_address, &AbiEncoderHelper::encode_erc20_balance_of(addr));
320                                balance_opcode.set_return_stack(true, 0, 0x0, 0x20);
321                                swap_opcodes.add(balance_opcode);
322
323                                trace!("transfer token={:?}, to={:?}, amount=from stack", token_from_address, cur_pool.get_address());
324                                let mut transfer_opcode = MulticallerCall::new_call(
325                                    token_from_address,
326                                    &AbiEncoderHelper::encode_erc20_transfer(funds_needed_at, U256::ZERO),
327                                );
328                                transfer_opcode.set_call_stack(true, 0, 0x24, 0x20);
329                                swap_opcodes.add(transfer_opcode);
330                                SwapAmountType::RelativeStack(0)
331                            }
332                            _ => {
333                                trace!("encode_swap_line_in_amount i == 0");
334                                trace!("transfer token={:?}, to={:?}, amount=from stack", token_from_address, cur_pool.get_address());
335                                let mut transfer_opcode = MulticallerCall::new_call(
336                                    token_from_address,
337                                    &AbiEncoderHelper::encode_erc20_transfer(funds_needed_at, U256::ZERO),
338                                );
339                                transfer_opcode.set_call_stack(false, 0, 0x24, 0x20);
340                                swap_opcodes.add(transfer_opcode);
341                                swap_path.amount_in
342                            }
343                        }
344                    } else {
345                        swap_path.amount_in
346                    }
347                } else {
348                    swap_path.amount_in
349                }
350
351                     */
352                swap_path.amount_in
353            } else {
354                SwapAmountType::RelativeStack(0)
355            };
356
357             */
358
359            /*let swap_to: Address = if let Some(next_pool) = next_pool {
360                match &self.abi_encoder.preswap_requirement(next_pool.as_ref()) {
361                    PreswapRequirement::Transfer(next_funds_to) => *next_funds_to,
362                    _ => self.multicaller_address,
363                }
364            } else {
365                funds_to
366            };*/
367
368            let swap_to = next_pool
369                .map(|x| match x.get_address() {
370                    kabu_types_entities::PoolId::Address(addr) => addr,
371                    kabu_types_entities::PoolId::B256(_) => self.multicaller_address, // fallback to multicaller_address
372                })
373                .unwrap_or(self.multicaller_address);
374
375            trace!("swap_to {:?}", swap_to);
376
377            self.opcodes_encoder.encode_swap_in_amount_provided(
378                &mut swap_opcodes,
379                self.abi_encoder.as_ref(),
380                token_from_address,
381                token_to_address,
382                amount_in,
383                cur_pool.as_ref(),
384                next_pool.map(|next_pool| next_pool.as_ref()),
385                MulticallerOpcodesPayload::Empty,
386                self.multicaller_address,
387            )?;
388
389            amount_in = RelativeStack(0);
390        }
391        Ok(swap_opcodes)
392    }
393
394    pub fn encode_tips(
395        &self,
396        swap_opcodes: MulticallerCalls,
397        token_address: Address,
398        min_balance: U256,
399        tips: U256,
400        to: Address,
401    ) -> Result<MulticallerCalls> {
402        let mut tips_opcodes = swap_opcodes.clone();
403
404        let call_data = if token_address == TokenAddressEth::WETH {
405            trace!("encode_multicaller_transfer_tips_weth");
406            AbiEncoderHelper::encode_multicaller_transfer_tips_weth(min_balance, tips, to)
407        } else {
408            trace!("encode_multicaller_transfer_tips");
409            AbiEncoderHelper::encode_multicaller_transfer_tips(token_address, min_balance, tips, to)
410        };
411        tips_opcodes.add(MulticallerCall::new_internal_call(&call_data));
412        Ok(tips_opcodes)
413    }
414}