kabu_execution_multicaller/pool_opcodes_encoder/
uniswap3.rs

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