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}