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