kabu_execution_multicaller/pool_opcodes_encoder/
curve.rs1use alloy_primitives::{Address, U256};
2use eyre::{eyre, Result};
3use lazy_static::lazy_static;
4use std::collections::HashMap;
5use tracing::trace;
6
7use crate::opcodes_helpers::OpcodesHelpers;
8use crate::pool_abi_encoder::ProtocolAbiSwapEncoderTrait;
9use crate::pool_opcodes_encoder::swap_opcodes_encoders::MulticallerOpcodesPayload;
10use crate::pool_opcodes_encoder::SwapOpcodesEncoderTrait;
11use kabu_defi_abi::AbiEncoderHelper;
12use kabu_defi_address_book::TokenAddressEth;
13use kabu_types_blockchain::{MulticallerCall, MulticallerCalls};
14use kabu_types_entities::Pool;
15use kabu_types_entities::{PreswapRequirement, SwapAmountType};
16
17pub struct CurveSwapOpcodesEncoder;
18
19lazy_static! {
20 static ref NEED_BALANCE_MAP : HashMap<Address, bool> = {
21 let mut hm = HashMap::new();
22 hm.insert("0xD51a44d3FaE010294C616388b506AcdA1bfAAE46".parse::<Address>().unwrap(), true);
23 hm.insert("0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7".parse::<Address>().unwrap(), true);
24 hm.insert("0xA5407eAE9Ba41422680e2e00537571bcC53efBfD".parse::<Address>().unwrap(), true); hm
26 };
27}
28
29impl CurveSwapOpcodesEncoder {
30 fn need_balance(address: Address) -> bool {
31 *NEED_BALANCE_MAP.get(&address).unwrap_or(&false)
32 }
33}
34
35impl SwapOpcodesEncoderTrait for CurveSwapOpcodesEncoder {
36 #[allow(clippy::too_many_arguments)]
37 fn encode_swap_in_amount_provided(
38 &self,
39 swap_opcodes: &mut MulticallerCalls,
40 abi_encoder: &dyn ProtocolAbiSwapEncoderTrait,
41 token_from_address: Address,
42 token_to_address: Address,
43 amount_in: SwapAmountType,
44 cur_pool: &dyn Pool,
45 next_pool: Option<&dyn Pool>,
46 payload: MulticallerOpcodesPayload,
47 multicaller: Address,
48 ) -> Result<()> {
49 let pool_id = cur_pool.get_address();
51 let pool_address = match pool_id {
52 kabu_types_entities::PoolId::Address(addr) => addr,
53 kabu_types_entities::PoolId::B256(_) => {
54 return Err(eyre!("B256 pool ID variant is not supported for Curve pools"));
55 }
56 };
57
58 let in_native = if cur_pool.is_native() { TokenAddressEth::is_weth(&token_from_address) } else { false };
59 let out_native = if cur_pool.is_native() { TokenAddressEth::is_weth(&token_to_address) } else { false };
60
61 trace!(
62 "curve swap for pool={:?} native={} amount={:?} from {} to {}",
63 cur_pool.get_address(),
64 cur_pool.is_native(),
65 amount_in,
66 token_from_address,
67 token_to_address
68 );
69
70 let mut opcodes: Vec<(MulticallerCall, u32, usize)> = Vec::new();
71
72 if in_native {
73 let mut swap_opcode = MulticallerCall::new_call_with_value(
75 pool_address,
76 &abi_encoder.encode_swap_in_amount_provided(
77 cur_pool,
78 token_from_address,
79 token_to_address,
80 amount_in.unwrap_or_default(),
81 multicaller,
82 payload.encode()?,
83 )?,
84 amount_in.unwrap_or_default(),
85 );
86
87 if !Self::need_balance(pool_address) {
88 swap_opcode.set_return_stack(true, 0, 0x0, 0x20);
89 }
90
91 opcodes.push((
93 MulticallerCall::new_call(token_from_address, &AbiEncoderHelper::encode_weth_withdraw(amount_in.unwrap_or_default())),
94 0x4,
95 0x20,
96 ));
97 opcodes.push((swap_opcode, abi_encoder.swap_in_amount_offset(cur_pool, token_from_address, token_to_address).unwrap(), 0x20));
98 } else {
99 opcodes.push((
101 MulticallerCall::new_call(
102 token_from_address,
103 &AbiEncoderHelper::encode_erc20_approve(pool_address, amount_in.unwrap_or_default()),
104 ),
105 0x24,
106 0x20,
107 ));
108
109 let mut swap_opcode = MulticallerCall::new_call(
111 pool_address,
112 &abi_encoder.encode_swap_in_amount_provided(
113 cur_pool,
114 token_from_address,
115 token_to_address,
116 amount_in.unwrap_or_default(),
117 multicaller,
118 payload.encode()?,
119 )?,
120 );
121
122 if !Self::need_balance(pool_address) {
123 swap_opcode.set_return_stack(true, 0, 0x0, 0x20);
124 }
125 opcodes.push((swap_opcode, abi_encoder.swap_in_amount_offset(cur_pool, token_from_address, token_to_address).unwrap(), 0x20));
126 }
127
128 swap_opcodes.merge(OpcodesHelpers::build_multiple_stack(amount_in, opcodes, Some(token_from_address))?);
129
130 if out_native {
131 let mut weth_deposit_opcode =
132 MulticallerCall::new_call_with_value(token_to_address, &AbiEncoderHelper::encode_weth_deposit(), U256::ZERO);
133 weth_deposit_opcode.set_call_stack(true, 0, 0x0, 0x0);
134 swap_opcodes.add(weth_deposit_opcode);
135 }
136
137 if let Some(next_pool) = next_pool {
138 if Self::need_balance(pool_address) {
139 let mut balance_opcode =
140 MulticallerCall::new_static_call(token_to_address, &AbiEncoderHelper::encode_erc20_balance_of(multicaller));
141 balance_opcode.set_return_stack(true, 0, 0x0, 0x20);
142 swap_opcodes.add(balance_opcode);
143 }
144
145 if let PreswapRequirement::Transfer(addr) = next_pool.preswap_requirement() {
146 trace!("transfer token={:?}, to={:?}, amount=stack_rel_0", token_to_address, addr);
147
148 let mut transfer_opcode =
149 MulticallerCall::new_call(token_to_address, &AbiEncoderHelper::encode_erc20_transfer(addr, U256::ZERO));
150 transfer_opcode.set_call_stack(true, 0, 0x24, 0x20);
151 swap_opcodes.add(transfer_opcode);
152 }
153 }
154 Ok(())
155 }
156
157 fn encode_swap_out_amount_provided(
158 &self,
159 _swap_opcodes: &mut MulticallerCalls,
160 _abi_encoder: &dyn ProtocolAbiSwapEncoderTrait,
161 _token_from_address: Address,
162 _token_to_address: Address,
163 _amount_out: SwapAmountType,
164 _cur_pool: &dyn Pool,
165 _next_pool: Option<&dyn Pool>,
166 _payload: MulticallerOpcodesPayload,
167 _multicaller_address: Address,
168 ) -> Result<()> {
169 Err(eyre!("NOT_IMPLEMENTED"))
170 }
171}