circles_pathfinder/lib.rs
1//! # Circles Pathfinder
2//!
3//! Pathfinding and flow matrix calculation for the Circles protocol.
4//!
5//! This crate provides efficient pathfinding algorithms and flow matrix generation
6//! for the Circles universal basic income protocol, with ready-to-use types for
7//! smart contract interactions.
8//!
9//! ## Quick Start
10//!
11//! ### High-level API (Recommended)
12//!
13//! ```rust,no_run
14//! use circles_pathfinder::{FindPathParams, prepare_flow_for_contract};
15//! use alloy_primitives::{Address, aliases::U192, U256};
16//!
17//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
18//! let params = FindPathParams {
19//! from: "0x123...".parse()?,
20//! to: "0x456...".parse()?,
21//! target_flow: U256::from(1_000_000_000_000_000_000u64), // 1 CRC
22//! use_wrapped_balances: Some(true),
23//! from_tokens: None,
24//! to_tokens: None,
25//! exclude_from_tokens: None,
26//! exclude_to_tokens: None,
27//! simulated_balances: None,
28//! max_transfers: None,
29//! };
30//!
31//! // One function call gets contract-ready data
32//! let path_data = prepare_flow_for_contract("https://rpc.circles.com", params).await?;
33//!
34//! // Ready for smart contract calls
35//! let (vertices, edges, streams, coords) = path_data.to_contract_params();
36//! // contract.some_function(vertices, edges, streams, coords)
37//! # Ok(())
38//! # }
39//! ```
40//!
41//! ### Low-level API (Advanced)
42//!
43//! ```rust,no_run
44//! use circles_pathfinder::{find_path, create_flow_matrix};
45//! use alloy_primitives::{Address, aliases::U192};
46//!
47//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
48//! // Step 1: Find path
49//! let transfers = find_path(
50//! "https://rpc.circles.com",
51//! "0x123...".parse()?,
52//! "0x456...".parse()?,
53//! U192::from(1000u64),
54//! true
55//! ).await?;
56//!
57//! // Step 2: Create flow matrix
58//! let matrix = create_flow_matrix(
59//! "0x123...".parse()?,
60//! "0x456...".parse()?,
61//! U192::from(1000u64),
62//! &transfers
63//! )?;
64//! # Ok(())
65//! # }
66//! ```
67//!
68//! ## Modules
69//!
70//! - `hub` - Circles Hub contract types and conversions
71//! - `rpc` - RPC communication and pathfinding
72//! - `flow` - Flow matrix calculation
73//! - `packing` - Coordinate packing utilities
74//! - `convenience` - High-level convenience functions
75//!
76//! ## Features
77//!
78//! - **Fast pathfinding** using Circles RPC endpoints
79//! - **Hub contract integration** with ready-to-use types
80//! - **Type safety** with `alloy-primitives`
81//! - **Efficient packing** for on-chain storage
82//! - **Comprehensive testing** with real-world scenarios
83
84mod convenience;
85mod flow;
86pub mod hub;
87mod packing;
88mod rpc;
89
90use alloy_primitives::{U256, aliases::U192};
91
92// Core public API - the main functions users need
93pub use flow::create_flow_matrix;
94pub mod path;
95
96// RPC functionality
97pub use circles_types::FindPathParams;
98pub use rpc::{find_path, find_path_with_params};
99
100// Hub contract integration types and functions
101use alloy_primitives::Address;
102use alloy_sol_types::sol;
103pub use hub::PathData;
104
105// High-level convenience functions
106pub use convenience::{
107 encode_redeem_flow_matrix, encode_redeem_trusted_data, get_available_flow,
108 prepare_flow_for_contract, prepare_flow_for_contract_simple,
109};
110
111pub use path::{
112 assert_no_netted_flow_mismatch, compute_netted_flow, expected_unwrapped_totals,
113 replace_wrapped_tokens, shrink_path_values, token_info_map_from_path, wrapped_totals_from_path,
114};
115
116// Utility functions for advanced users
117pub use packing::{pack_coordinates, transform_to_flow_vertices};
118
119#[derive(Clone, Debug)]
120pub struct FlowMatrix {
121 pub flow_vertices: Vec<Address>,
122 pub flow_edges: Vec<FlowEdge>,
123 pub streams: Vec<Stream>,
124 pub packed_coordinates: Vec<u8>,
125 pub source_coordinate: U256,
126}
127
128sol!(
129 /// Standard Circles Hub FlowEdge struct matching the contract ABI
130 #[derive(Debug, PartialEq)]
131 struct FlowEdge {
132 uint16 streamSinkId;
133 uint192 amount;
134 }
135
136 /// Standard Circles Hub Stream struct matching the contract ABI
137 #[derive(Debug, PartialEq)]
138 struct Stream {
139 uint16 sourceCoordinate;
140 uint16[] flowEdgeIds;
141 bytes data;
142 }
143
144 function redeem(bytes32 id, bytes calldata data) external;
145);
146
147/// Errors that can occur during pathfinding and flow matrix operations.
148#[derive(thiserror::Error, Debug)]
149pub enum PathfinderError {
150 /// Flow matrix terminal sum doesn't match expected value.
151 ///
152 /// This occurs when the sum of all terminal flow edges (edges that reach
153 /// the destination) doesn't equal the expected transfer amount. This
154 /// usually indicates an issue with the transfer path or RPC data.
155 ///
156 /// # Example
157 /// ```text
158 /// PathfinderError::Imbalanced {
159 /// terminal_sum: 800,
160 /// expected: 1000
161 /// }
162 /// ```
163 #[error("terminal sum {terminal_sum} != expected {expected}")]
164 Imbalanced {
165 /// Actual sum of terminal flow edges
166 terminal_sum: U192,
167 /// Expected total flow amount
168 expected: U192,
169 },
170
171 /// RPC transport/client error (HTTP/WS or deserialization).
172 #[error("rpc transport error: {0}")]
173 Transport(#[from] circles_rpc::CirclesRpcError),
174
175 /// JSON-RPC payload error returned by the server or an invalid response body.
176 #[error("rpc response error: {0}")]
177 RpcResponse(String),
178}