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}