Skip to main content

circles_types/
pathfinding.rs

1use alloy_primitives::{aliases::U192, Address, Bytes, U256};
2use serde::{Deserialize, Serialize};
3
4/// Simulated balance for path finding.
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct SimulatedBalance {
7    pub holder: Address,
8    pub token: Address,
9    pub amount: U256,
10    pub is_wrapped: bool,
11    pub is_static: bool,
12}
13
14/// Simulated trust connection for path finding.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct SimulatedTrust {
17    pub truster: Address,
18    pub trustee: Address,
19}
20
21/// Path finding parameters for `circlesV2_findPath`.
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct FindPathParams {
24    #[serde(rename = "Source")]
25    pub from: Address,
26    #[serde(rename = "Sink")]
27    pub to: Address,
28    #[serde(rename = "TargetFlow")]
29    pub target_flow: U256,
30    #[serde(rename = "UseWrappedBalances")]
31    pub use_wrapped_balances: Option<bool>,
32    #[serde(rename = "FromTokens")]
33    pub from_tokens: Option<Vec<Address>>,
34    #[serde(rename = "ToTokens")]
35    pub to_tokens: Option<Vec<Address>>,
36    #[serde(rename = "ExcludeFromTokens")]
37    pub exclude_from_tokens: Option<Vec<Address>>,
38    #[serde(rename = "ExcludeToTokens")]
39    pub exclude_to_tokens: Option<Vec<Address>>,
40    #[serde(rename = "SimulatedBalances")]
41    pub simulated_balances: Option<Vec<SimulatedBalance>>,
42    #[serde(rename = "SimulatedTrusts")]
43    pub simulated_trusts: Option<Vec<SimulatedTrust>>,
44    #[serde(rename = "MaxTransfers")]
45    pub max_transfers: Option<u32>,
46}
47
48/// A single transfer step in a pathfinding result.
49/// This is the pathfinding version; different from the contract-facing `TransferStep`.
50#[derive(Debug, Clone, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub struct PathfindingTransferStep {
53    pub from: Address,
54    pub to: Address,
55    pub token_owner: String, // TypeScript uses string, keeping it for API compatibility
56    pub value: U256,
57}
58
59/// Result of pathfinding computation.
60#[derive(Debug, Clone, Serialize, Deserialize)]
61#[serde(rename_all = "camelCase")]
62pub struct PathfindingResult {
63    pub max_flow: U256,
64    pub transfers: Vec<PathfindingTransferStep>,
65}
66
67/// Flow edge structure for `operateFlowMatrix`.
68/// Corresponds to `TypeDefinitions.FlowEdge` in Hub V2.
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct FlowEdgeStruct {
71    #[serde(rename = "streamSinkId")]
72    pub stream_sink_id: u16,
73    pub amount: U192, // uint192 in Solidity
74}
75
76/// Stream structure for `operateFlowMatrix`.
77/// Corresponds to `TypeDefinitions.Stream` in Hub V2.
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct StreamStruct {
80    #[serde(rename = "sourceCoordinate")]
81    pub source_coordinate: u16,
82    #[serde(rename = "flowEdgeIds")]
83    pub flow_edge_ids: Vec<u16>,
84    pub data: Bytes, // Handles both Uint8Array and Hex from TypeScript
85}
86
87/// Flow matrix for ABI encoding, used with Hub V2 `operateFlowMatrix`.
88/// This is the pathfinding version; different from the contract-facing `FlowMatrix`.
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct PathfindingFlowMatrix {
91    #[serde(rename = "flowVertices")]
92    pub flow_vertices: Vec<String>, // Keep as strings for API compatibility
93    #[serde(rename = "flowEdges")]
94    pub flow_edges: Vec<FlowEdgeStruct>,
95    pub streams: Vec<StreamStruct>,
96    #[serde(rename = "packedCoordinates")]
97    pub packed_coordinates: String, // Hex string
98    #[serde(rename = "sourceCoordinate")]
99    pub source_coordinate: u16, // Convenience field, not part of ABI
100}
101
102/// Advanced transfer options.
103/// Extends `FindPathParams` to add transfer-specific options.
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct AdvancedTransferOptions {
106    // All fields from FindPathParams except from, to, targetFlow
107    pub use_wrapped_balances: Option<bool>,
108    pub from_tokens: Option<Vec<Address>>,
109    pub to_tokens: Option<Vec<Address>>,
110    pub exclude_from_tokens: Option<Vec<Address>>,
111    pub exclude_to_tokens: Option<Vec<Address>>,
112    pub simulated_balances: Option<Vec<SimulatedBalance>>,
113    pub simulated_trusts: Option<Vec<SimulatedTrust>>,
114    pub max_transfers: Option<u32>,
115
116    /// Custom data to attach to the transfer (optional)
117    pub tx_data: Option<Bytes>,
118}
119
120impl AdvancedTransferOptions {
121    /// Convert to `FindPathParams` with the required from/to/targetFlow fields.
122    pub fn to_find_path_params(
123        self,
124        from: Address,
125        to: Address,
126        target_flow: U256,
127    ) -> FindPathParams {
128        FindPathParams {
129            from,
130            to,
131            target_flow,
132            use_wrapped_balances: self.use_wrapped_balances,
133            from_tokens: self.from_tokens,
134            to_tokens: self.to_tokens,
135            exclude_from_tokens: self.exclude_from_tokens,
136            exclude_to_tokens: self.exclude_to_tokens,
137            simulated_balances: self.simulated_balances,
138            simulated_trusts: self.simulated_trusts,
139            max_transfers: self.max_transfers,
140        }
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::{FindPathParams, SimulatedTrust};
147    use alloy_primitives::{Address, U256};
148    use serde_json::json;
149
150    #[test]
151    fn serializes_simulated_trusts_with_rpc_field_name() {
152        let params = FindPathParams {
153            from: Address::repeat_byte(0x11),
154            to: Address::repeat_byte(0x22),
155            target_flow: U256::from(42u64),
156            use_wrapped_balances: Some(true),
157            from_tokens: None,
158            to_tokens: None,
159            exclude_from_tokens: None,
160            exclude_to_tokens: None,
161            simulated_balances: None,
162            simulated_trusts: Some(vec![SimulatedTrust {
163                truster: Address::repeat_byte(0x33),
164                trustee: Address::repeat_byte(0x44),
165            }]),
166            max_transfers: Some(7),
167        };
168
169        let serialized = serde_json::to_value(params).expect("serialize path params");
170
171        assert_eq!(
172            serialized["SimulatedTrusts"],
173            json!([{
174                "truster": format!("{:#x}", Address::repeat_byte(0x33)),
175                "trustee": format!("{:#x}", Address::repeat_byte(0x44)),
176            }])
177        );
178    }
179}
180
181// ============================================================================
182// Original Flow Types (moved from lib.rs)
183// ============================================================================
184
185/// Edge in the flow graph (sinkId 1 == final hop).
186/// This is the original version from lib.rs.
187#[derive(Clone, Debug, Serialize, Deserialize)]
188pub struct FlowEdge {
189    pub stream_sink_id: u16,
190    pub amount: U192,
191}
192
193/// Stream with byte data.
194/// This is the original version from lib.rs.
195#[derive(Clone, Debug, Serialize, Deserialize)]
196pub struct Stream {
197    pub source_coordinate: u16,
198    pub flow_edge_ids: Vec<u16>,
199    pub data: Vec<u8>,
200}
201
202/// Transfer step for internal flow calculations.
203/// This is the original version from lib.rs—different from `PathfindingTransferStep`.
204#[derive(Clone, Debug, Serialize, Deserialize)]
205pub struct TransferStep {
206    pub from_address: Address,
207    pub to_address: Address,
208    pub token_owner: Address,
209    pub value: U192,
210}
211
212/// ABI-ready matrix returned by `create_flow_matrix`.
213/// This is the original version from lib.rs—different from `PathfindingFlowMatrix`.
214#[derive(Clone, Debug)]
215pub struct FlowMatrix {
216    pub flow_vertices: Vec<Address>,
217    pub flow_edges: Vec<FlowEdge>,
218    pub streams: Vec<Stream>,
219    pub packed_coordinates: Vec<u8>,
220    pub source_coordinate: u16,
221}