kabu_execution_multicaller/
swapline_encoder.rs

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