1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/// Macro to generate two-hop swapper helper methods
/// Assumes the struct has:
/// - pool_a() method returning &(PoolKey, Address)
/// - pool_b() method returning &(PoolKey, Address)
/// - intermediate_token() method returning Result<Currency>
#[macro_export]
macro_rules! impl_two_hop_swapper_methods {
($struct_name:ident) => {
impl $struct_name {
/// Determine the two-hop path tokens using is_to_b
///
/// This function determines the token path for a two-hop swap based on the
/// swap direction. The `is_to_b` parameter indicates the overall swap
/// direction (towards pool_b).
///
/// # Arguments
///
/// * `is_to_b` - If true, swap direction is towards pool_b (input -> pool_a
/// -> pool_b -> output) If false, swap direction is reversed (output ->
/// pool_b -> pool_a -> input)
///
/// # Returns
///
/// Returns a tuple `(token0, token1, token2)` where:
/// - `token0` is the input token (first token in the path)
/// - `token1` is the intermediate token (shared between the two pools)
/// - `token2` is the output token (last token in the path)
///
/// # Example
///
/// ```ignore
/// let (input_token, intermediate_token, output_token) = swapper.determine_two_hop_path_tokens(true)?;
/// ```
pub fn determine_two_hop_path_tokens(
&self,
is_to_pool_b: bool,
) -> anyhow::Result<(
uniswap_sdk_core::prelude::Currency,
uniswap_sdk_core::prelude::Currency,
uniswap_sdk_core::prelude::Currency,
)> {
$crate::pool_swappers::common::determine_two_hop_path_tokens(
&self.pool_a().0,
&self.pool_b().0,
is_to_pool_b,
)
}
/// Get the swap directions for both pools based on the overall swap
/// direction
///
/// This function determines if each pool swaps from tokenA to tokenB based
/// on the overall swap direction.
///
/// # Arguments
///
/// * `is_to_b` - The overall swap direction (towards pool_b)
///
/// # Returns
///
/// Returns a tuple `(pool_a_is_to_b, pool_b_is_to_b)` where:
/// - `pool_a_is_to_b`: true if pool_a swaps from tokenA -> tokenB, false if
/// swapping tokenB -> tokenA
/// - `pool_b_is_to_b`: true if pool_b swaps from tokenA -> tokenB, false if
/// swapping tokenB -> tokenA
pub fn get_swap_directions(&self, is_to_pool_b: bool) -> (bool, bool) {
let (token0, token1, _) = self
.determine_two_hop_path_tokens(is_to_pool_b)
.expect("Failed to determine two-hop path tokens");
let pool_a = self.pool_a().0.clone();
let pool_b = self.pool_b().0.clone();
// token0 is the input token for pool_a
// If token0 is pool_a's token_a, we're swapping A -> B (is_to_b = true)
let pool_a_is_to_b = if pool_a.token_b == token1 {
if pool_a.token_a == token0 {
true
} else {
false
}
} else {
if pool_a.token_b == token0 {
false
} else {
true
}
};
// token1 is the intermediate token (input for pool_b)
// If token1 is pool_b's token_a, we're swapping A -> B (is_to_b = true)
let pool_b_is_to_b = if pool_b.token_a == token1 {
if pool_b.token_b == token0 {
false
} else {
true
}
} else {
if pool_b.token_a == token0 {
true
} else {
false
}
};
(pool_a_is_to_b, pool_b_is_to_b)
}
/// Get the is_to_intermediate flags for both pools based on overall swap
/// direction
///
/// This function determines whether each pool's swap is going towards the
/// intermediate token based on the overall swap direction (is_to_b).
///
/// # Arguments
///
/// * `is_to_b` - The overall swap direction (towards pool_b)
///
/// # Returns
///
/// Returns a tuple `(pool_a_is_to_intermediate, pool_b_is_to_intermediate)`
/// where:
/// - `pool_a_is_to_intermediate`: true if pool_a's output token is the
/// intermediate token
/// - `pool_b_is_to_intermediate`: always false (pool_b receives
/// intermediate as input)
pub fn get_intermediate_flags(&self, is_to_pool_b: bool) -> (bool, bool) {
let (token0, token1, _) = self
.determine_two_hop_path_tokens(is_to_pool_b)
.expect("Failed to determine two-hop path tokens");
let pool_a_is_to_intermediate = if token1 == self.pool_a().0.token_b {
token0 == self.pool_a().0.token_a
} else {
token0 == self.pool_a().0.token_b
};
let pool_b_is_to_intermediate = !pool_a_is_to_intermediate;
(pool_a_is_to_intermediate, pool_b_is_to_intermediate)
}
/// Get currency0 (the non-intermediate token in pool_a)
///
/// This is an internal helper function that returns the token in pool_a
/// that is not the intermediate token.
pub fn currency0_internal(&self) -> uniswap_sdk_core::prelude::Currency {
let intermediate =
self.intermediate_token().expect("Failed to get intermediate token");
if self.pool_a().0.token_a == intermediate {
self.pool_a().0.token_b.clone()
} else {
self.pool_a().0.token_a.clone()
}
}
/// Get currency1 (the non-intermediate token in pool_b)
///
/// This is an internal helper function that returns the token in pool_b
/// that is not the intermediate token.
pub fn currency1_internal(&self) -> uniswap_sdk_core::prelude::Currency {
let intermediate =
self.intermediate_token().expect("Failed to get intermediate token");
if self.pool_b().0.token_a == intermediate {
self.pool_b().0.token_b.clone()
} else {
self.pool_b().0.token_a.clone()
}
}
}
};
}