Skip to main content

wp_evm_base/
types.rs

1//! Base data types shared across all layers and families.
2//!
3//! Pure data records. No methods beyond derive and `From/Into`.
4
5use alloy_primitives::{Address, Bytes, U256};
6
7/// A single EVM call: target + calldata + msg.value.
8///
9/// This is the minimal unit produced by L4 plan functions and consumed by L5/L6.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Call {
12    pub target: Address,
13    pub calldata: Bytes,
14    pub value: U256,
15}
16
17/// A declared token approval requirement.
18///
19/// L4 plan functions emit these alongside calls. L5 composer reads on-chain
20/// allowances and decides whether an actual approve call is needed.
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct TokenApproval {
23    pub token: Address,
24    pub spender: Address,
25    pub min_amount: U256,
26}
27
28/// A token + amount pair, family- and protocol-agnostic.
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct TokenAmount {
31    pub token: Address,
32    pub amount: U256,
33}
34
35/// Output of a plan function: a bundle of calls + declared approvals + value.
36///
37/// Family-agnostic. Composer (L5) aggregates `PlanFragment`s from multiple
38/// protocol facades into a single `ComposedTx`.
39#[derive(Debug, Clone, PartialEq, Eq, Default)]
40pub struct PlanFragment {
41    pub calls: Vec<Call>,
42    pub approvals: Vec<TokenApproval>,
43    pub value: U256,
44}
45
46/// Slippage tolerance in basis points (1 bps = 0.01%).
47///
48/// Stored as `u16`; 10_000 = 100%. Construct via `SlippageBps::new(50)` for 0.5%.
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
50pub struct SlippageBps(u16);
51
52impl SlippageBps {
53    pub const fn new(bps: u16) -> Self {
54        assert!(bps <= 10_000, "slippage cannot exceed 100%");
55        Self(bps)
56    }
57    pub const fn as_bps(self) -> u16 {
58        self.0
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use alloy_primitives::{address, bytes};
66
67    #[test]
68    fn call_constructs_with_zero_value() {
69        let call = Call {
70            target: address!("0x0000000000000000000000000000000000000001"),
71            calldata: bytes!("deadbeef"),
72            value: U256::ZERO,
73        };
74        assert_eq!(call.value, U256::ZERO);
75        assert_eq!(call.calldata.len(), 4);
76    }
77
78    #[test]
79    fn slippage_bps_accepts_10000_bps() {
80        let _ok = SlippageBps::new(10_000);
81    }
82
83    #[test]
84    #[should_panic(expected = "slippage cannot exceed 100%")]
85    fn slippage_bps_rejects_over_10000_bps() {
86        let _ = SlippageBps::new(10_001);
87    }
88}