kabu_execution_multicaller/pool_opcodes_encoder/
uniswap3.rs

1use crate::opcodes_helpers::OpcodesHelpers;
2use crate::pool_abi_encoder::ProtocolAbiSwapEncoderTrait;
3use crate::pool_opcodes_encoder::SwapOpcodesEncoderTrait;
4use crate::pool_opcodes_encoder::swap_opcodes_encoders::MulticallerOpcodesPayload;
5use alloy_primitives::{Address, Bytes, U256};
6use eyre::{OptionExt, eyre};
7use kabu_defi_abi::AbiEncoderHelper;
8use kabu_types_blockchain::{MulticallerCall, MulticallerCalls};
9use kabu_types_market::{Pool, PreswapRequirement};
10use kabu_types_swap::SwapAmountType;
11use tracing::trace;
12
13pub struct UniswapV3SwapOpcodesEncoder {}
14
15impl SwapOpcodesEncoderTrait for UniswapV3SwapOpcodesEncoder {
16    fn encode_swap_in_amount_provided(
17        &self,
18        swap_opcodes: &mut MulticallerCalls,
19        abi_encoder: &dyn ProtocolAbiSwapEncoderTrait,
20        token_from_address: Address,
21        token_to_address: Address,
22        amount_in: SwapAmountType,
23        cur_pool: &dyn Pool,
24        next_pool: Option<&dyn Pool>,
25        payload: MulticallerOpcodesPayload,
26        multicaller_address: Address,
27    ) -> eyre::Result<()> {
28        let inside_call_payload = if payload.is_empty() { Bytes::from(token_from_address.to_vec()) } else { payload.encode()? };
29
30        let swap_to: Address = if let Some(next_pool) = next_pool {
31            match next_pool.preswap_requirement() {
32                PreswapRequirement::Transfer(next_funds_to) => next_funds_to,
33                _ => multicaller_address,
34            }
35        } else {
36            multicaller_address
37        };
38
39        let pool_address = match cur_pool.get_address() {
40            kabu_types_market::PoolId::Address(addr) => addr,
41            kabu_types_market::PoolId::B256(_) => return Err(eyre!("Pool ID is B256, expected Address")),
42        };
43
44        let mut swap_opcode = MulticallerCall::new_call(
45            pool_address,
46            &abi_encoder.encode_swap_in_amount_provided(
47                cur_pool,
48                token_from_address,
49                token_to_address,
50                amount_in.unwrap_or_default(),
51                swap_to,
52                inside_call_payload,
53            )?,
54        );
55
56        swap_opcode.set_return_stack(
57            true,
58            0,
59            abi_encoder.swap_in_amount_return_offset(cur_pool, token_from_address, token_to_address).unwrap(),
60            0x20,
61        );
62
63        swap_opcodes.merge(OpcodesHelpers::build_call_stack(
64            amount_in,
65            swap_opcode,
66            abi_encoder.swap_in_amount_offset(cur_pool, token_from_address, token_to_address).ok_or_eyre("NO_OFFSET")?,
67            0x20,
68            Some(token_from_address),
69        )?);
70
71        if next_pool.is_some() {
72            trace!("has next pool");
73            if let Some(x) = abi_encoder.swap_in_amount_return_script(cur_pool, token_from_address, token_to_address) {
74                let calc_opcode = MulticallerCall::new_calculation_call(&x);
75                swap_opcodes.add(calc_opcode);
76            }
77        }
78        Ok(())
79    }
80
81    fn encode_swap_out_amount_provided(
82        &self,
83        _swap_opcodes: &mut MulticallerCalls,
84        _abi_encoder: &dyn ProtocolAbiSwapEncoderTrait,
85        _token_from_address: Address,
86        _token_to_address: Address,
87        _amount_out: SwapAmountType,
88        _cur_pool: &dyn Pool,
89        _next_pool: Option<&dyn Pool>,
90        _payload: MulticallerOpcodesPayload,
91        _multicaller_address: Address,
92    ) -> eyre::Result<()> {
93        Err(eyre!("NOT_IMPLEMENTED"))
94    }
95
96    fn encode_flash_swap_in_amount_provided(
97        &self,
98        swap_opcodes: &mut MulticallerCalls,
99        abi_encoder: &dyn ProtocolAbiSwapEncoderTrait,
100        token_from_address: Address,
101        token_to_address: Address,
102        amount_in: SwapAmountType,
103        flash_pool: &dyn Pool,
104        prev_pool: Option<&dyn Pool>,
105        payload: MulticallerOpcodesPayload,
106        multicaller_address: Address,
107    ) -> eyre::Result<()> {
108        let swap_to = match prev_pool {
109            Some(prev_pool) => match prev_pool.preswap_requirement() {
110                PreswapRequirement::Transfer(funds_to) => {
111                    trace!("other transfer to previous pool: funds_to={:?}, prev_pool={:?}", funds_to, prev_pool.get_address());
112                    funds_to
113                }
114                _ => {
115                    trace!("other swap to multicaller, prev_pool={:?}", prev_pool.get_address());
116                    multicaller_address
117                }
118            },
119            None => multicaller_address,
120        };
121
122        let payload = match payload {
123            MulticallerOpcodesPayload::Opcodes(payload) => {
124                trace!("uniswap v3 transfer token={:?}, to={:?}, amount={:?}", token_from_address, flash_pool.get_address(), amount_in);
125                let mut payload = payload;
126                let mut transfer_opcode = MulticallerCall::new_call(
127                    token_from_address,
128                    &AbiEncoderHelper::encode_erc20_transfer(
129                        match flash_pool.get_address() {
130                            kabu_types_market::PoolId::Address(addr) => addr,
131                            kabu_types_market::PoolId::B256(_) => return Err(eyre!("Pool ID is B256, expected Address")),
132                        },
133                        amount_in.unwrap_or_default(),
134                    ),
135                );
136
137                if amount_in.is_not_set() {
138                    transfer_opcode.set_call_stack(false, 1, 0x24, 0x20);
139                }
140
141                payload.add(transfer_opcode);
142
143                MulticallerOpcodesPayload::Opcodes(payload)
144            }
145            _ => payload,
146        };
147
148        let inside_call_bytes = payload.encode()?;
149
150        trace!(
151            "uniswap v3 flash swap in amount for pool={:?}  from {} to {} amount={:?}",
152            flash_pool.get_address(),
153            token_from_address,
154            token_to_address,
155            amount_in,
156        );
157        let pool_address = match flash_pool.get_address() {
158            kabu_types_market::PoolId::Address(addr) => addr,
159            kabu_types_market::PoolId::B256(_) => return Err(eyre!("Pool ID is B256, expected Address")),
160        };
161
162        let mut swap_opcode = MulticallerCall::new_call(
163            pool_address,
164            &abi_encoder.encode_swap_in_amount_provided(
165                flash_pool,
166                token_from_address,
167                token_to_address,
168                amount_in.unwrap_or_default(),
169                swap_to,
170                inside_call_bytes,
171            )?,
172        );
173
174        if amount_in.is_not_set() {
175            swap_opcode.set_call_stack(
176                false,
177                0,
178                abi_encoder.swap_in_amount_offset(flash_pool, token_from_address, token_to_address).unwrap(),
179                0x20,
180            );
181        }
182
183        swap_opcodes.add(swap_opcode);
184
185        Ok(())
186    }
187
188    fn encode_flash_swap_out_amount_provided(
189        &self,
190        swap_opcodes: &mut MulticallerCalls,
191        abi_encoder: &dyn ProtocolAbiSwapEncoderTrait,
192        token_from_address: Address,
193        token_to_address: Address,
194        amount_out: SwapAmountType,
195        flash_pool: &dyn Pool,
196        next_pool: Option<&dyn Pool>,
197        payload: MulticallerOpcodesPayload,
198        multicaller_address: Address,
199    ) -> eyre::Result<()> {
200        let swap_to = next_pool.and_then(|next_pool| next_pool.preswap_requirement().address()).unwrap_or(multicaller_address);
201
202        let payload = if let MulticallerOpcodesPayload::Opcodes(inside_opcodes) = payload {
203            let mut inside_opcodes = inside_opcodes;
204            //if next_pool.is_none() {
205            trace!("retflash transfer token={:?}, to={:?}, amount=stack_norel_1", token_from_address, flash_pool.get_address());
206            let mut transfer_opcode = MulticallerCall::new_call(
207                token_from_address,
208                &AbiEncoderHelper::encode_erc20_transfer(
209                    match flash_pool.get_address() {
210                        kabu_types_market::PoolId::Address(addr) => addr,
211                        kabu_types_market::PoolId::B256(_) => return Err(eyre!("Pool ID is B256, expected Address")),
212                    },
213                    U256::ZERO,
214                ),
215            );
216            transfer_opcode.set_call_stack(false, 1, 0x24, 0x20);
217
218            inside_opcodes.add(transfer_opcode);
219
220            MulticallerOpcodesPayload::Opcodes(inside_opcodes)
221        } else {
222            payload
223        };
224
225        let inside_call_bytes = payload.encode()?;
226
227        trace!(
228            "uniswap v3 swap out amount provided for pool={:?}, from={} to={} amount_out={:?} receiver={} inside_opcodes_len={}",
229            flash_pool.get_address(),
230            token_from_address,
231            token_to_address,
232            amount_out,
233            swap_to,
234            inside_call_bytes.len()
235        );
236
237        let pool_address = match flash_pool.get_address() {
238            kabu_types_market::PoolId::Address(addr) => addr,
239            kabu_types_market::PoolId::B256(_) => return Err(eyre!("Pool ID is B256, expected Address")),
240        };
241
242        let mut swap_opcode = MulticallerCall::new_call(
243            pool_address,
244            &abi_encoder.encode_swap_out_amount_provided(
245                flash_pool,
246                token_from_address,
247                token_to_address,
248                amount_out.unwrap_or_default(),
249                swap_to,
250                inside_call_bytes,
251            )?,
252        );
253
254        if amount_out.is_not_set() {
255            trace!("uniswap v3 swap out amount is not set");
256
257            swap_opcode.set_call_stack(
258                true,
259                0,
260                abi_encoder.swap_out_amount_offset(flash_pool, token_from_address, token_to_address).unwrap(),
261                0x20,
262            );
263
264            swap_opcodes.add(MulticallerCall::new_calculation_call(&Bytes::from(vec![0x2, 0x2A, 0x00])));
265        };
266
267        swap_opcodes.add(swap_opcode);
268
269        Ok(())
270    }
271}