wp_evm_ramses_core/data.rs
1//! Ramses-family data records.
2//!
3//! Re-exports shared types from `wp-evm-v3-core::data` where the ABI is
4//! identical, and defines Ramses-specific types where it differs.
5//!
6//! # ABI differences from Uniswap V3
7//!
8//! Ramses-fork NFPMs use `int24 tickSpacing` at field position 2 of
9//! `MintParams` (instead of Uniswap V3's `uint24 fee`). The `positions()`
10//! return also uses `int24 tickSpacing` rather than `uint24 fee`.
11//!
12//! Verified against:
13//! - Shadow: `Shadow-Exchange/shadow-core` `contracts/CL/periphery/interfaces/
14//! INonfungiblePositionManager.sol` (11-field MintParams, 10-field positions())
15//! - Slipstream: `velodrome-finance/slipstream` `contracts/periphery/interfaces/
16//! INonfungiblePositionManager.sol` (12-field MintParams with sqrtPriceX96,
17//! 12-field positions() with nonce/operator)
18
19use alloy_primitives::{Address, B256, U256};
20
21pub use wp_evm_v3_core::data::{
22 CollectFeesParams, ExactInParams, ExactOutParams, PlanFragment, PoolState, Quote,
23 RemoveAndCollectParams, RemoveLiquidityParams, TickInfo,
24};
25
26/// Parameters for an `add_liquidity` plan on a Ramses-family NFPM.
27///
28/// Uses `tick_spacing: i32` instead of `fee: u32` because Ramses-fork NFPMs
29/// identify pools by `(token0, token1, tickSpacing)` — there is no `fee`
30/// field in `MintParams`.
31///
32/// This replaces `wp_evm_v3_core::data::AddLiquidityParams` for all
33/// Ramses-family protocols (Shadow, Slipstream, Aerodrome).
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct RamsesAddLiquidityParams {
36 pub token0: Address,
37 pub token1: Address,
38 /// Pool-identifying tick spacing. Read from `PoolState.tick_spacing`.
39 pub tick_spacing: i32,
40 pub tick_lower: i32,
41 pub tick_upper: i32,
42 pub amount0_desired: U256,
43 pub amount1_desired: U256,
44 pub recipient: Address,
45}
46
47/// Hydrated state of a Ramses-family NFPM position.
48///
49/// Uses `tick_spacing: i32` instead of `fee: u32` because Ramses-fork
50/// `positions()` returns `int24 tickSpacing` at that field position.
51///
52/// Compatible with both Shadow (10-field `positions()` return, no nonce/operator)
53/// and Slipstream / Aerodrome (12-field return, has nonce/operator — those are
54/// dropped since they're not needed by plan/quote functions).
55#[derive(Debug, Clone, PartialEq, Eq)]
56pub struct PositionState {
57 pub token_id: U256,
58 pub owner: Address,
59 pub token0: Address,
60 pub token1: Address,
61 pub tick_spacing: i32,
62 pub tick_lower: i32,
63 pub tick_upper: i32,
64 pub liquidity: u128,
65 pub fees_owed_0: U256,
66 pub fees_owed_1: U256,
67}
68
69/// A resolved gauge reward claim for one gauge.
70///
71/// Mirrors arbitrage `GaugeRewardsItem`. `reward_tokens` and `token_ids`
72/// are independent arrays (different lengths permitted — N reward tokens
73/// vs M positions); the encoder places them positionally as
74/// `claimClGaugeRewards(_gauges, _tokens, _nfpTokenIds)`.
75#[derive(Debug, Clone, PartialEq, Eq)]
76pub struct GaugeClaim {
77 pub gauge: Address,
78 pub reward_tokens: Vec<Address>,
79 pub token_ids: Vec<U256>,
80}
81
82/// Raw `earned` reads for one gauge, laid out token-by-position.
83///
84/// `earned[t][p] == Gauge.earned(reward_tokens[t], token_ids[p])`. Produced
85/// by the provider reader `gauge_earned_grids`; consumed by the pure
86/// `build_gauge_claims` pruner. Always rectangular:
87/// `earned.len() == reward_tokens.len()` and each row's len ==
88/// `token_ids.len()`.
89#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct GaugeEarnedGrid {
91 pub gauge: Address,
92 pub reward_tokens: Vec<Address>,
93 pub token_ids: Vec<U256>,
94 pub earned: Vec<Vec<U256>>,
95}
96
97/// Per-protocol configuration for a Ramses-family DEX.
98///
99/// Ramses pools are keyed by `(token0, token1, tickSpacing)` instead of
100/// Uniswap V3's `(token0, token1, fee)`. `tick_spacings` enumerates the
101/// valid tick spacings supported by the protocol.
102///
103/// Adding a new Ramses-fork DEX = creating a new protocol facade with a
104/// `pub const CONFIG: RamsesProtocolConfig = ...`. No family code changes.
105///
106/// **CREATE2 deployment**: Shadow / Ramses-core uses an independent
107/// `RamsesV3PoolDeployer` contract (≠ factory) for CREATE2. The
108/// `pool_deployer` field is the actual CREATE2 caller used by
109/// `pool_address::compute`. Velodrome-family protocols (Slipstream /
110/// Aerodrome) deploy via EIP-1167 Clones instead and set
111/// `pool_deployer = Address::ZERO`; their facade `pool_address` body
112/// passes `cfg.factory` as the deployer (the factory contract IS the
113/// CREATE2 caller for clone-pattern deployments).
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub struct RamsesProtocolConfig {
116 pub factory: Address,
117 /// CREATE2 deployer — `RamsesV3PoolDeployer` for Shadow-pattern,
118 /// `Address::ZERO` for EIP-1167-Clone-pattern (Slipstream / Aerodrome).
119 /// Read via `factory.ramsesV3PoolDeployer()` getter for CREATE2-deploying
120 /// Ramses forks; clone-pattern facades pass `cfg.factory` instead at the
121 /// `pool_address::compute` call site.
122 pub pool_deployer: Address,
123 pub router: Address,
124 pub position_mgr: Address,
125 pub init_code_hash: B256,
126 pub tick_spacings: &'static [i32],
127 pub multicall: Address,
128 pub quoter: Option<Address>,
129 pub voter: Address,
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use alloy_primitives::address;
136
137 #[test]
138 fn gauge_claim_holds_independent_token_and_position_arrays() {
139 let c = GaugeClaim {
140 gauge: address!("4444444444444444444444444444444444444444"),
141 reward_tokens: vec![
142 address!("1111111111111111111111111111111111111111"),
143 address!("2222222222222222222222222222222222222222"),
144 ],
145 token_ids: vec![U256::from(7u64)],
146 };
147 assert_eq!(c.reward_tokens.len(), 2);
148 assert_eq!(c.token_ids.len(), 1);
149 }
150
151 #[test]
152 fn gauge_earned_grid_is_rectangular_token_by_position() {
153 let g = GaugeEarnedGrid {
154 gauge: address!("4444444444444444444444444444444444444444"),
155 reward_tokens: vec![Address::ZERO, Address::ZERO],
156 token_ids: vec![U256::from(1u64), U256::from(2u64), U256::from(3u64)],
157 earned: vec![vec![U256::ZERO; 3], vec![U256::ZERO; 3]],
158 };
159 assert_eq!(g.earned.len(), g.reward_tokens.len());
160 assert_eq!(g.earned[0].len(), g.token_ids.len());
161 }
162}