wp-evm-base 0.1.2

Base layer (math, evm helpers, base types) for waterpump-evm
Documentation
//! Base data types shared across all layers and families.
//!
//! Pure data records. No methods beyond derive and `From/Into`.

use alloy_primitives::{Address, Bytes, U256};

/// A single EVM call: target + calldata + msg.value.
///
/// This is the minimal unit produced by L4 plan functions and consumed by L5/L6.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Call {
    pub target: Address,
    pub calldata: Bytes,
    pub value: U256,
}

/// A declared token approval requirement.
///
/// L4 plan functions emit these alongside calls. L5 composer reads on-chain
/// allowances and decides whether an actual approve call is needed.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TokenApproval {
    pub token: Address,
    pub spender: Address,
    pub min_amount: U256,
}

/// A token + amount pair, family- and protocol-agnostic.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TokenAmount {
    pub token: Address,
    pub amount: U256,
}

/// Output of a plan function: a bundle of calls + declared approvals + value.
///
/// Family-agnostic. Composer (L5) aggregates `PlanFragment`s from multiple
/// protocol facades into a single `ComposedTx`.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct PlanFragment {
    pub calls: Vec<Call>,
    pub approvals: Vec<TokenApproval>,
    pub value: U256,
}

/// Slippage tolerance in basis points (1 bps = 0.01%).
///
/// Stored as `u16`; 10_000 = 100%. Construct via `SlippageBps::new(50)` for 0.5%.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SlippageBps(u16);

impl SlippageBps {
    pub const fn new(bps: u16) -> Self {
        assert!(bps <= 10_000, "slippage cannot exceed 100%");
        Self(bps)
    }
    pub const fn as_bps(self) -> u16 {
        self.0
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use alloy_primitives::{address, bytes};

    #[test]
    fn call_constructs_with_zero_value() {
        let call = Call {
            target: address!("0x0000000000000000000000000000000000000001"),
            calldata: bytes!("deadbeef"),
            value: U256::ZERO,
        };
        assert_eq!(call.value, U256::ZERO);
        assert_eq!(call.calldata.len(), 4);
    }

    #[test]
    fn slippage_bps_accepts_10000_bps() {
        let _ok = SlippageBps::new(10_000);
    }

    #[test]
    #[should_panic(expected = "slippage cannot exceed 100%")]
    fn slippage_bps_rejects_over_10000_bps() {
        let _ = SlippageBps::new(10_001);
    }
}