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
404#[derive(Debug, Clone)]
411pub struct PermitSingle {
412 details: PermitDetails,
413 spender: Bytes,
414 sig_deadline: BigUint,
415}
416
417impl PermitSingle {
418 pub fn new(details: PermitDetails, spender: Bytes, sig_deadline: BigUint) -> Self {
419 Self { details, spender, sig_deadline }
420 }
421
422 pub fn details(&self) -> &PermitDetails {
423 &self.details
424 }
425
426 pub fn spender(&self) -> &Bytes {
427 &self.spender
428 }
429
430 pub fn sig_deadline(&self) -> &BigUint {
431 &self.sig_deadline
432 }
433}
434
435#[derive(Debug, Clone)]
443pub struct PermitDetails {
444 token: Bytes,
445 amount: BigUint,
446 expiration: BigUint,
447 nonce: BigUint,
448}
449
450impl PermitDetails {
451 pub fn new(token: Bytes, amount: BigUint, expiration: BigUint, nonce: BigUint) -> Self {
452 Self { token, amount, expiration, nonce }
453 }
454
455 pub fn token(&self) -> &Bytes {
456 &self.token
457 }
458
459 pub fn amount(&self) -> &BigUint {
460 &self.amount
461 }
462
463 pub fn expiration(&self) -> &BigUint {
464 &self.expiration
465 }
466
467 pub fn nonce(&self) -> &BigUint {
468 &self.nonce
469 }
470}
471
472impl PartialEq for PermitSingle {
473 fn eq(&self, other: &Self) -> bool {
474 self.details == other.details && self.spender == other.spender
475 }
477}
478
479impl PartialEq for PermitDetails {
480 fn eq(&self, other: &Self) -> bool {
481 self.token == other.token && self.amount == other.amount && self.nonce == other.nonce
482 }
484}
485
486#[derive(Clone, Debug)]
495pub struct EncodingContext {
496 pub router_address: Option<Bytes>,
497 pub group_token_in: Bytes,
498 pub group_token_out: Bytes,
499}
500
501#[derive(PartialEq)]
502pub enum Strategy {
503 Single,
504 Sequential,
505 Split,
506}
507
508#[cfg(any(test, feature = "test-utils"))]
511pub fn default_token(address: Bytes) -> Token {
512 Token::new(&address, "", 0, 0, &[Some(60_000u64)], Default::default(), 100)
513}
514
515mod tests {
516 use super::*;
517
518 struct MockProtocolComponent {
519 id: String,
520 protocol_system: String,
521 }
522
523 impl From<MockProtocolComponent> for ProtocolComponent {
524 fn from(component: MockProtocolComponent) -> Self {
525 ProtocolComponent {
526 id: component.id,
527 protocol_system: component.protocol_system,
528 tokens: vec![],
529 protocol_type_name: "".to_string(),
530 chain: Default::default(),
531 contract_addresses: vec![],
532 static_attributes: Default::default(),
533 change: Default::default(),
534 creation_tx: Default::default(),
535 created_at: Default::default(),
536 }
537 }
538 }
539
540 #[test]
541 fn test_swap_new() {
542 let component = MockProtocolComponent {
543 id: "i-am-an-id".to_string(),
544 protocol_system: "uniswap_v2".to_string(),
545 };
546 let user_data = Bytes::from("0x1234");
547 let swap = Swap::new(
548 component,
549 default_token(Bytes::from("0x12")),
550 default_token(Bytes::from("0x34")),
551 BigUint::ZERO,
552 )
553 .with_split(0.5)
554 .with_user_data(user_data.clone());
555
556 assert_eq!(swap.token_in().address, Bytes::from("0x12"));
557 assert_eq!(swap.token_out().address, Bytes::from("0x34"));
558 assert_eq!(swap.component().protocol_system, "uniswap_v2");
559 assert_eq!(swap.component().id, "i-am-an-id");
560 assert_eq!(swap.split(), 0.5);
561 assert_eq!(swap.user_data(), &Some(user_data));
562 }
563}