1use std::sync::Arc;
2
3#[cfg(feature = "evm")]
4use alloy::primitives::{Address, U256};
5use clap::ValueEnum;
6use num_bigint::BigUint;
7use serde::{Deserialize, Serialize};
8use tycho_common::{
9 models::{protocol::ProtocolComponent, token::Token},
10 simulation::protocol_sim::ProtocolSim,
11 Bytes,
12};
13
14use crate::encoding::serde_primitives::biguint_string;
15
16#[derive(Clone, Debug, PartialEq, ValueEnum, Serialize, Deserialize, Default)]
32pub enum UserTransferType {
33 TransferFromPermit2,
34 #[default]
35 TransferFrom,
36 UseVaultsFunds,
37}
38
39#[derive(Clone, Debug, Default, Deserialize, Serialize)]
44pub struct ClientFeeParams {
45 client_fee_bps: u16,
47 client_fee_receiver: Bytes,
49 #[serde(with = "biguint_string")]
52 max_client_contribution: BigUint,
53 #[serde(with = "biguint_string")]
55 deadline: BigUint,
56 client_signature: Bytes,
58}
59
60impl ClientFeeParams {
61 pub fn new(
63 client_fee_receiver: Bytes,
64 client_signature: Bytes,
65 deadline: BigUint,
66 client_fee_bps: u16,
67 ) -> Self {
68 Self {
69 client_fee_bps,
70 client_fee_receiver,
71 max_client_contribution: BigUint::ZERO,
72 deadline,
73 client_signature,
74 }
75 }
76
77 pub fn new_without_fee(
79 client_fee_receiver: Bytes,
80 client_signature: Bytes,
81 deadline: BigUint,
82 ) -> Self {
83 Self {
84 client_fee_bps: 0,
85 client_fee_receiver,
86 max_client_contribution: BigUint::ZERO,
87 deadline,
88 client_signature,
89 }
90 }
91
92 pub fn with_max_client_contribution(mut self, max_client_contribution: BigUint) -> Self {
93 self.max_client_contribution = max_client_contribution;
94 self
95 }
96}
97
98#[cfg(feature = "evm")]
99impl ClientFeeParams {
100 pub fn into_abi_params(self) -> (u16, Address, U256, U256, Vec<u8>) {
102 let receiver = if self.client_fee_receiver.is_empty() {
103 Address::ZERO
104 } else {
105 Address::from_slice(&self.client_fee_receiver)
106 };
107 (
108 self.client_fee_bps,
109 receiver,
110 U256::from_be_slice(
111 &self
112 .max_client_contribution
113 .to_bytes_be(),
114 ),
115 U256::from_be_slice(&self.deadline.to_bytes_be()),
116 self.client_signature.to_vec(),
117 )
118 }
119}
120
121#[derive(Clone, Default, Debug, Deserialize, Serialize)]
124pub struct Solution {
125 sender: Bytes,
127 receiver: Bytes,
129 token_in: Bytes,
131 #[serde(with = "biguint_string")]
133 amount_in: BigUint,
134 token_out: Bytes,
136 #[serde(with = "biguint_string")]
138 min_amount_out: BigUint,
139 swaps: Vec<Swap>,
141 user_transfer_type: UserTransferType,
143}
144
145impl Solution {
146 pub fn new(
147 sender: Bytes,
148 receiver: Bytes,
149 token_in: Bytes,
150 token_out: Bytes,
151 amount_in: BigUint,
152 min_amount_out: BigUint,
153 swaps: Vec<Swap>,
154 ) -> Self {
155 Self {
156 sender,
157 receiver,
158 token_in,
159 token_out,
160 amount_in,
161 min_amount_out,
162 swaps,
163 user_transfer_type: UserTransferType::TransferFrom,
164 }
165 }
166 pub fn sender(&self) -> &Bytes {
167 &self.sender
168 }
169 pub fn receiver(&self) -> &Bytes {
170 &self.receiver
171 }
172
173 pub fn token_in(&self) -> &Bytes {
174 &self.token_in
175 }
176
177 pub fn amount_in(&self) -> &BigUint {
178 &self.amount_in
179 }
180
181 pub fn token_out(&self) -> &Bytes {
182 &self.token_out
183 }
184
185 pub fn min_amount_out(&self) -> &BigUint {
186 &self.min_amount_out
187 }
188
189 pub fn swaps(&self) -> &[Swap] {
190 &self.swaps
191 }
192
193 pub fn user_transfer_type(&self) -> &UserTransferType {
194 &self.user_transfer_type
195 }
196
197 pub fn with_sender(mut self, sender: Bytes) -> Self {
198 self.sender = sender;
199 self
200 }
201
202 pub fn with_receiver(mut self, receiver: Bytes) -> Self {
203 self.receiver = receiver;
204 self
205 }
206
207 pub fn with_token_in(mut self, token_in: Bytes) -> Self {
208 self.token_in = token_in;
209 self
210 }
211
212 pub fn with_amount_in(mut self, amount_in: BigUint) -> Self {
213 self.amount_in = amount_in;
214 self
215 }
216
217 pub fn with_token_out(mut self, token_out: Bytes) -> Self {
218 self.token_out = token_out;
219 self
220 }
221
222 pub fn with_min_amount_out(mut self, min_amount_out: BigUint) -> Self {
223 self.min_amount_out = min_amount_out;
224 self
225 }
226
227 pub fn with_swaps(mut self, swaps: Vec<Swap>) -> Self {
228 self.swaps = swaps;
229 self
230 }
231
232 pub fn with_user_transfer_type(mut self, user_transfer_type: UserTransferType) -> Self {
233 self.user_transfer_type = user_transfer_type;
234 self
235 }
236}
237
238#[derive(Clone, Debug, Deserialize, Serialize)]
240pub struct Swap {
241 component: ProtocolComponent,
243 token_in: Token,
245 token_out: Token,
247 #[serde(default)]
249 split: f64,
250 user_data: Option<Bytes>,
252 #[serde(skip)]
254 protocol_state: Option<Arc<dyn ProtocolSim>>,
255 estimated_amount_in: Option<BigUint>,
258 estimated_gas: BigUint,
260}
261
262impl Swap {
263 pub fn new<T: Into<ProtocolComponent>>(
264 component: T,
265 token_in: Token,
266 token_out: Token,
267 estimated_gas: BigUint,
268 ) -> Self {
269 Self {
270 component: component.into(),
271 token_in,
272 token_out,
273 split: 0.0,
274 user_data: None,
275 protocol_state: None,
276 estimated_amount_in: None,
277 estimated_gas,
278 }
279 }
280
281 pub fn with_split(mut self, split: f64) -> Self {
283 self.split = split;
284 self
285 }
286
287 pub fn with_user_data(mut self, user_data: Bytes) -> Self {
289 self.user_data = Some(user_data);
290 self
291 }
292
293 pub fn with_protocol_state(mut self, protocol_state: Arc<dyn ProtocolSim>) -> Self {
295 self.protocol_state = Some(protocol_state);
296 self
297 }
298
299 pub fn with_estimated_amount_in(mut self, estimated_amount_in: BigUint) -> Self {
301 self.estimated_amount_in = Some(estimated_amount_in);
302 self
303 }
304
305 pub fn component(&self) -> &ProtocolComponent {
306 &self.component
307 }
308
309 pub fn token_in(&self) -> &Token {
310 &self.token_in
311 }
312
313 pub fn token_out(&self) -> &Token {
314 &self.token_out
315 }
316
317 pub fn split(&self) -> f64 {
318 self.split
319 }
320
321 pub fn user_data(&self) -> &Option<Bytes> {
322 &self.user_data
323 }
324
325 pub fn protocol_state(&self) -> &Option<Arc<dyn ProtocolSim>> {
326 &self.protocol_state
327 }
328
329 pub fn estimated_amount_in(&self) -> &Option<BigUint> {
330 &self.estimated_amount_in
331 }
332
333 pub fn estimated_gas(&self) -> &BigUint {
334 &self.estimated_gas
335 }
336}
337
338impl PartialEq for Swap {
339 fn eq(&self, other: &Self) -> bool {
340 self.component() == other.component() &&
341 self.token_in().address == other.token_in().address &&
342 self.token_out().address == other.token_out().address &&
343 self.split() == other.split() &&
344 self.user_data() == other.user_data() &&
345 self.estimated_amount_in() == other.estimated_amount_in() &&
346 self.estimated_gas() == other.estimated_gas()
347 }
348}
349
350#[derive(Clone, Debug)]
359pub struct EncodedSolution {
360 swaps: Vec<u8>,
362 interacting_with: Bytes,
364 function_signature: String,
366 n_tokens: usize,
368 estimated_gas: BigUint,
370}
371
372impl EncodedSolution {
373 pub(crate) fn new(
374 swaps: Vec<u8>,
375 interacting_with: Bytes,
376 function_signature: String,
377 n_tokens: usize,
378 estimated_gas: BigUint,
379 ) -> Self {
380 Self { swaps, interacting_with, function_signature, n_tokens, estimated_gas }
381 }
382
383 pub fn swaps(&self) -> &[u8] {
384 &self.swaps
385 }
386
387 pub fn interacting_with(&self) -> &Bytes {
388 &self.interacting_with
389 }
390
391 pub fn function_signature(&self) -> &str {
392 &self.function_signature
393 }
394
395 pub fn n_tokens(&self) -> usize {
396 self.n_tokens
397 }
398
399 pub fn estimated_gas(&self) -> &BigUint {
400 &self.estimated_gas
401 }
402
403 pub fn client_fee_signature_offset(&self) -> usize {
405 let name = self
406 .function_signature
407 .split('(')
408 .next()
409 .unwrap_or("");
410 let head_params = match name {
411 "singleSwap" |
412 "singleSwapUsingVault" |
413 "sequentialSwap" |
414 "sequentialSwapUsingVault" => 7,
415 "splitSwap" | "splitSwapUsingVault" => 8,
416 "singleSwapPermit2" | "sequentialSwapPermit2" => 14,
417 "splitSwapPermit2" => 15,
418 _ => 0,
419 };
420 4 + head_params * 32 + 192
422 }
423}
424
425#[derive(Debug, Clone)]
432pub struct PermitSingle {
433 details: PermitDetails,
434 spender: Bytes,
435 sig_deadline: BigUint,
436}
437
438impl PermitSingle {
439 pub fn new(details: PermitDetails, spender: Bytes, sig_deadline: BigUint) -> Self {
440 Self { details, spender, sig_deadline }
441 }
442
443 pub fn details(&self) -> &PermitDetails {
444 &self.details
445 }
446
447 pub fn spender(&self) -> &Bytes {
448 &self.spender
449 }
450
451 pub fn sig_deadline(&self) -> &BigUint {
452 &self.sig_deadline
453 }
454}
455
456#[derive(Debug, Clone)]
464pub struct PermitDetails {
465 token: Bytes,
466 amount: BigUint,
467 expiration: BigUint,
468 nonce: BigUint,
469}
470
471impl PermitDetails {
472 pub fn new(token: Bytes, amount: BigUint, expiration: BigUint, nonce: BigUint) -> Self {
473 Self { token, amount, expiration, nonce }
474 }
475
476 pub fn token(&self) -> &Bytes {
477 &self.token
478 }
479
480 pub fn amount(&self) -> &BigUint {
481 &self.amount
482 }
483
484 pub fn expiration(&self) -> &BigUint {
485 &self.expiration
486 }
487
488 pub fn nonce(&self) -> &BigUint {
489 &self.nonce
490 }
491}
492
493impl PartialEq for PermitSingle {
494 fn eq(&self, other: &Self) -> bool {
495 self.details == other.details && self.spender == other.spender
496 }
498}
499
500impl PartialEq for PermitDetails {
501 fn eq(&self, other: &Self) -> bool {
502 self.token == other.token && self.amount == other.amount && self.nonce == other.nonce
503 }
505}
506
507#[derive(Clone, Debug)]
516pub struct EncodingContext {
517 pub router_address: Option<Bytes>,
518 pub group_token_in: Bytes,
519 pub group_token_out: Bytes,
520}
521
522#[derive(PartialEq)]
523pub enum Strategy {
524 Single,
525 Sequential,
526 Split,
527}
528
529#[cfg(any(test, feature = "test-utils"))]
532pub fn default_token(address: Bytes) -> Token {
533 Token::new(&address, "", 0, 0, &[Some(60_000u64)], Default::default(), 100)
534}
535
536mod tests {
537 use super::*;
538
539 struct MockProtocolComponent {
540 id: String,
541 protocol_system: String,
542 }
543
544 impl From<MockProtocolComponent> for ProtocolComponent {
545 fn from(component: MockProtocolComponent) -> Self {
546 ProtocolComponent {
547 id: component.id,
548 protocol_system: component.protocol_system,
549 tokens: vec![],
550 protocol_type_name: "".to_string(),
551 chain: Default::default(),
552 contract_addresses: vec![],
553 static_attributes: Default::default(),
554 change: Default::default(),
555 creation_tx: Default::default(),
556 created_at: Default::default(),
557 }
558 }
559 }
560
561 #[test]
562 fn test_swap_new() {
563 let component = MockProtocolComponent {
564 id: "i-am-an-id".to_string(),
565 protocol_system: "uniswap_v2".to_string(),
566 };
567 let user_data = Bytes::from("0x1234");
568 let swap = Swap::new(
569 component,
570 default_token(Bytes::from("0x12")),
571 default_token(Bytes::from("0x34")),
572 BigUint::ZERO,
573 )
574 .with_split(0.5)
575 .with_user_data(user_data.clone());
576
577 assert_eq!(swap.token_in().address, Bytes::from("0x12"));
578 assert_eq!(swap.token_out().address, Bytes::from("0x34"));
579 assert_eq!(swap.component().protocol_system, "uniswap_v2");
580 assert_eq!(swap.component().id, "i-am-an-id");
581 assert_eq!(swap.split(), 0.5);
582 assert_eq!(swap.user_data(), &Some(user_data));
583 }
584}