kabu_execution_multicaller/pool_opcodes_encoder/
uniswap2.rs1use 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;
7use kabu_defi_abi::AbiEncoderHelper;
8use kabu_types_blockchain::{MulticallerCall, MulticallerCalls};
9use kabu_types_entities::{Pool, PoolId, PreswapRequirement, SwapAmountType};
10use tracing::{trace, warn};
11
12pub struct UniswapV2SwapOpcodesEncoder;
13
14impl SwapOpcodesEncoderTrait for UniswapV2SwapOpcodesEncoder {
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 swap_to = next_pool.and_then(|next_pool| next_pool.preswap_requirement().address()).unwrap_or(multicaller_address);
29
30 trace!(
31 "uniswap v2 get out amount for pool={:?}, amount={:?} from {} to {}",
32 cur_pool.get_address(),
33 amount_in,
34 token_from_address,
35 token_to_address
36 );
37
38 let pool_address = match cur_pool.get_address() {
40 PoolId::Address(addr) => addr,
41 PoolId::B256(_) => return Err(eyre!("B256 pool ID not supported for UniswapV2")),
42 };
43 let get_out_amount_opcode = MulticallerCall::new_internal_call(&AbiEncoderHelper::encode_multicaller_uni2_get_out_amount(
44 token_from_address,
45 token_to_address,
46 pool_address,
47 amount_in.unwrap_or_default(),
48 cur_pool.get_fee(),
49 ));
50
51 swap_opcodes.merge(OpcodesHelpers::build_call_stack(amount_in, get_out_amount_opcode, 0x24, 0x20, Some(token_from_address))?);
53
54 let mut swap_opcode = MulticallerCall::new_call(
56 pool_address,
57 &abi_encoder.encode_swap_out_amount_provided(
58 cur_pool,
59 token_from_address,
60 token_to_address,
61 U256::from(1),
62 swap_to,
63 Bytes::new(),
64 )?,
65 );
66
67 swap_opcode.set_call_stack(
69 true,
70 0,
71 abi_encoder.swap_out_amount_offset(cur_pool, token_from_address, token_to_address).unwrap(),
72 0x20,
73 );
74
75 swap_opcodes.add(swap_opcode);
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 flash_pool_address = match flash_pool.get_address() {
109 PoolId::Address(addr) => addr,
110 PoolId::B256(_) => return Err(eyre!("B256 pool ID not supported for UniswapV2")),
111 };
112
113 let payload = if let MulticallerOpcodesPayload::Opcodes(inside_opcodes) = &payload {
114 let mut inside_opcodes = inside_opcodes.clone();
115
116 match amount_in {
117 SwapAmountType::Set(amount) => {
118 trace!("uniswap v2 transfer token={:?}, to={:?}, amount={}", token_from_address, flash_pool.get_address(), amount);
120
121 inside_opcodes.add(MulticallerCall::new_call(
122 token_from_address,
123 &AbiEncoderHelper::encode_erc20_transfer(flash_pool_address, amount),
124 ));
125 }
126 _ => {
127 warn!("InAmountTypeNotSet");
128 }
129 }
130
131 if let Some(prev_pool) = prev_pool {
133 if let PreswapRequirement::Transfer(swap_to) = prev_pool.preswap_requirement() {
134 trace!("uniswap v2 transfer token_to_address={:?}, funds_to={:?} amount=stack_norel_0", token_to_address, swap_to);
135 let mut transfer_opcode =
136 MulticallerCall::new_call(token_to_address, &AbiEncoderHelper::encode_erc20_transfer(swap_to, U256::ZERO));
137 transfer_opcode.set_call_stack(false, 0, 0x24, 0x20);
138 inside_opcodes.insert(transfer_opcode);
139 }
140 }
141 MulticallerOpcodesPayload::Opcodes(inside_opcodes)
142 } else {
143 payload
144 };
145
146 let inside_call_bytes = payload.encode()?;
147
148 trace!("uniswap v2 get out amount for pool={:?}, amount={:?}", flash_pool.get_address(), amount_in);
151 let mut get_out_amount_opcode = MulticallerCall::new_internal_call(&AbiEncoderHelper::encode_multicaller_uni2_get_out_amount(
152 token_from_address,
153 token_to_address,
154 flash_pool_address,
155 amount_in.unwrap_or_default(),
156 flash_pool.get_fee(),
157 ));
158
159 if amount_in.is_not_set() {
161 get_out_amount_opcode.set_call_stack(false, 0, 0x24, 0x20);
162 }
163
164 let mut swap_opcode = MulticallerCall::new_call(
166 flash_pool_address,
167 &abi_encoder.encode_swap_out_amount_provided(
168 flash_pool,
169 token_from_address,
170 token_to_address,
171 U256::ZERO,
172 multicaller_address,
173 inside_call_bytes,
174 )?,
175 );
176
177 swap_opcode.set_call_stack(
179 true,
180 0,
181 abi_encoder.swap_out_amount_offset(flash_pool, token_from_address, token_to_address).unwrap(),
182 0x20,
183 );
184
185 swap_opcodes.add(get_out_amount_opcode).add(swap_opcode);
186
187 Ok(())
188 }
189
190 fn encode_flash_swap_out_amount_provided(
191 &self,
192 swap_opcodes: &mut MulticallerCalls,
193 abi_encoder: &dyn ProtocolAbiSwapEncoderTrait,
194 token_from_address: Address,
195 token_to_address: Address,
196 amount_out: SwapAmountType,
197 flash_pool: &dyn Pool,
198 next_pool: Option<&dyn Pool>,
199 payload: MulticallerOpcodesPayload,
200 multicaller_address: Address,
201 ) -> eyre::Result<()> {
202 let flash_pool_address = match flash_pool.get_address() {
204 PoolId::Address(addr) => addr,
205 PoolId::B256(_) => return Err(eyre!("B256 pool ID not supported for UniswapV2")),
206 };
207
208 let swap_to = next_pool.and_then(|next_pool| next_pool.preswap_requirement().address()).unwrap_or(multicaller_address);
210
211 let payload = if let MulticallerOpcodesPayload::Opcodes(inside_opcodes) = &payload {
213 let mut inside_opcodes = inside_opcodes.clone();
214
215 let mut get_in_amount_opcode = MulticallerCall::new_internal_call(&AbiEncoderHelper::encode_multicaller_uni2_get_in_amount(
216 token_from_address,
217 token_to_address,
218 flash_pool_address,
219 amount_out.unwrap_or_default(),
220 flash_pool.get_fee(),
221 ));
222
223 if amount_out.is_not_set() {
225 get_in_amount_opcode.set_call_stack(false, 0, 0x24, 0x20);
226 }
227
228 inside_opcodes.insert(get_in_amount_opcode);
229
230 if swap_to != multicaller_address {
232 trace!("retflash transfer token={:?}, to={:?}, amount=stack_norel_0", token_to_address, swap_to);
233
234 let mut transfer_opcode =
235 MulticallerCall::new_call(token_to_address, &AbiEncoderHelper::encode_erc20_transfer(swap_to, U256::ZERO));
236 transfer_opcode.set_call_stack(false, 0, 0x24, 0x20);
237 inside_opcodes.add(transfer_opcode);
238 }
239
240 MulticallerOpcodesPayload::Opcodes(inside_opcodes)
241 } else {
242 payload
243 };
244
245 let inside_call_bytes = payload.encode()?;
247
248 trace!(
250 "uniswap v2 swap out amount provided for pool={:?}, from={} to={} amount_out={:?} receiver={} inside_opcodes_len={}",
251 flash_pool.get_address(),
252 token_from_address,
253 token_to_address,
254 amount_out,
255 swap_to,
256 inside_call_bytes.len()
257 );
258 let mut swap_opcode = MulticallerCall::new_call(
259 flash_pool_address,
260 &abi_encoder.encode_swap_out_amount_provided(
261 flash_pool,
262 token_from_address,
263 token_to_address,
264 amount_out.unwrap_or_default(),
265 multicaller_address,
266 inside_call_bytes,
267 )?,
268 );
269
270 if amount_out.is_not_set() {
272 trace!("uniswap v2 amount not set");
273 swap_opcode.set_call_stack(
274 true,
275 0,
276 abi_encoder.swap_out_amount_offset(flash_pool, token_from_address, token_to_address).unwrap(),
277 0x20,
278 );
279 }
280
281 swap_opcodes.add(swap_opcode);
282 Ok(())
283 }
284}