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