scemadex_sdk/intent.rs
1use serde::{Deserialize, Serialize};
2
3use crate::primitives::{Address, Amount};
4
5/// What the caller is optimizing for. The RL policy weights its route search by
6/// this objective — and, crucially, can optimize *timing* and *footprint*, which
7/// static pathfinders cannot.
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
9pub enum Objective {
10 /// Best effective price / minimal slippage.
11 Price,
12 /// Fastest confirmation; price is secondary.
13 Speed,
14 /// Minimal MEV footprint — split and time the order to resist sandwiching.
15 Stealth,
16}
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
19pub enum Side {
20 Buy,
21 Sell,
22}
23
24/// Hard limits the solver must respect; a solution that violates any of these is
25/// rejected before bonding.
26#[derive(Clone, Debug, Serialize, Deserialize)]
27pub struct Constraints {
28 pub max_slippage_bps: u32,
29 /// Deadline in unix seconds; `0` means "no explicit deadline" in the scaffold.
30 pub deadline_unix: u64,
31 /// Optional cap on how many legs/splits the route may use.
32 pub max_legs: Option<u8>,
33}
34
35/// A declarative request: *what* the caller wants, not *how* to route it. The
36/// [`crate::policy::RoutePolicy`] turns this into a [`crate::policy::Solution`].
37#[derive(Clone, Debug, Serialize, Deserialize)]
38pub struct Intent {
39 pub input_mint: Address,
40 pub output_mint: Address,
41 pub amount_in: Amount,
42 pub side: Side,
43 pub objective: Objective,
44 pub constraints: Constraints,
45}
46
47impl Intent {
48 /// Stable content digest used as a key for metering, caching, and bonds.
49 ///
50 /// Uses an FNV-1a hash over the canonical JSON encoding to avoid pulling a
51 /// crypto-hash dependency into the lean core. Good enough as a scaffold key;
52 /// the `scematica` feature can swap in a stronger hash where it matters.
53 pub fn digest(&self) -> String {
54 let s = serde_json::to_string(self).unwrap_or_default();
55 let mut h: u64 = 0xcbf2_9ce4_8422_2325;
56 for b in s.bytes() {
57 h ^= b as u64;
58 h = h.wrapping_mul(0x0000_0100_0000_01b3);
59 }
60 format!("{h:016x}")
61 }
62}