penumbra_sdk_dex/
state_key.rs1use crate::{lp::position, DirectedTradingPair, TradingPair};
2use penumbra_sdk_asset::asset;
3use std::string::String;
4
5pub mod config {
6 pub fn dex_params() -> &'static str {
7 "dex/config/dex_params"
8 }
9}
10
11pub fn value_balance(asset_id: &asset::Id) -> String {
12 format!("dex/value_balance/{asset_id}")
13}
14
15pub fn positions(trading_pair: &TradingPair, position_id: &str) -> String {
16 format!("dex/positions/{trading_pair}/opened/{position_id}")
17}
18
19pub fn position_by_id(id: &position::Id) -> String {
22 format!("dex/position/{id}")
23}
24
25pub fn all_positions() -> &'static str {
26 "dex/position/"
27}
28
29pub mod candlesticks {
30
31 pub mod object {
32 pub fn block_executions() -> &'static str {
33 "dex/candlesticks/object/block_executions"
34 }
35
36 pub fn block_position_executions() -> &'static str {
37 "dex/candlesticks/object/block_position_executions"
38 }
39
40 pub fn block_swap_executions() -> &'static str {
41 "dex/candlesticks/object/block_swap_executions"
42 }
43 }
44
45 pub mod data {
46 use crate::DirectedTradingPair;
47
48 pub fn prefix() -> &'static str {
49 "dex/candlesticks/data/"
50 }
51
52 pub fn by_pair_and_height(pair: &DirectedTradingPair, height: u64) -> String {
53 format!("{}{}/{}/{height:020}", prefix(), &pair.start, &pair.end)
54 }
55
56 pub fn by_pair(pair: &DirectedTradingPair) -> String {
57 format!("{}{}/{}/", prefix(), &pair.start, &pair.end)
58 }
59 }
60}
61
62pub mod block_scoped {
63 pub mod active {
64 pub fn trading_pairs() -> &'static str {
65 "dex/block_scoped/active/trading_pairs"
66 }
67 }
68}
69
70pub fn output_data(height: u64, trading_pair: TradingPair) -> String {
71 format!(
72 "dex/output/{:020}/{}/{}",
73 height,
74 &trading_pair.asset_1(),
75 &trading_pair.asset_2()
76 )
77}
78
79pub fn swap_execution(height: u64, trading_pair: DirectedTradingPair) -> String {
80 format!(
81 "dex/swap_execution/{:020}/{}/{}",
82 height, &trading_pair.start, &trading_pair.end
83 )
84}
85
86pub fn swap_executions() -> &'static str {
87 "dex/swap_execution/"
88}
89
90pub fn arb_execution(height: u64) -> String {
91 format!("dex/arb_execution/{height:020}")
92}
93
94pub fn arb_executions() -> &'static str {
95 "dex/arb_execution/"
96}
97
98pub fn swap_flows() -> &'static str {
99 "dex/swap_flows"
100}
101
102pub fn pending_position_closures() -> &'static str {
103 "dex/pending_position_closures"
104}
105
106pub fn recently_accessed_assets() -> &'static str {
107 "dex/recently_accessed_assets"
108}
109
110pub fn pending_payloads() -> &'static str {
111 "dex/pending_payloads"
112}
113
114pub fn pending_outputs() -> &'static str {
115 "dex/pending_outputs"
116}
117
118pub fn aggregate_value() -> &'static str {
119 "dex/aggregate_value"
120}
121
122pub mod lqt {
123 pub mod v1 {
124 pub mod pair {
125 pub mod lookup {
126 use penumbra_sdk_asset::asset;
127
128 pub(crate) fn prefix(epoch_index: u64) -> String {
129 format!("dex/lqt/v1/pair/lookup/{epoch_index:020}/")
130 }
131
132 pub(crate) fn volume_by_pair(epoch_index: u64, asset: asset::Id) -> [u8; 76] {
140 let prefix_bytes = prefix(epoch_index);
141 let mut key = [0u8; 76];
142 key[0..44].copy_from_slice(prefix_bytes.as_bytes());
143 key[44..44 + 32].copy_from_slice(&asset.to_bytes());
144 key
145 }
146 }
147 }
148
149 pub mod lp {
150 pub mod lookup {
151 pub(crate) fn prefix(epoch_index: u64) -> String {
152 format!("dex/lqt/v1/lp/lookup/{epoch_index:020}/")
153 }
154
155 pub(crate) fn volume_by_position(
163 epoch_index: u64,
164 position_id: &crate::lp::position::Id,
165 ) -> [u8; 74] {
166 let prefix_bytes = prefix(epoch_index);
167 let mut key = [0u8; 74];
168 key[0..42].copy_from_slice(prefix_bytes.as_bytes());
169 key[42..42 + 32].copy_from_slice(&position_id.0);
170 key
171 }
172 }
173
174 pub mod by_volume {
175 use anyhow::{ensure, Result};
176 use penumbra_sdk_asset::asset;
177 use penumbra_sdk_num::Amount;
178
179 use crate::lp::position;
180
181 pub fn prefix(epoch_index: u64) -> String {
182 format!("dex/lqt/v1/lp/by_volume/{epoch_index:020}/")
183 }
184
185 pub fn prefix_with_asset(epoch_index: u64, asset: &asset::Id) -> [u8; 77] {
186 let prefix = prefix(epoch_index);
187 let mut key = [0u8; 77];
188 key[0..45].copy_from_slice(prefix.as_bytes());
189 key[45..45 + 32].copy_from_slice(&asset.to_bytes());
190 key
191 }
192
193 pub(crate) fn key(
199 epoch_index: u64,
200 asset: &asset::Id,
201 position: &position::Id,
202 volume: Amount,
203 ) -> [u8; 125] {
204 let prefix_bytes = prefix(epoch_index);
205 let mut key = [0u8; 125];
206 key[0..45].copy_from_slice(prefix_bytes.as_bytes());
207 key[45..45 + 32].copy_from_slice(&asset.to_bytes());
208 key[45 + 32..45 + 32 + 16].copy_from_slice(&(!volume).to_be_bytes());
209 key[45 + 32 + 16..45 + 32 + 16 + 32].copy_from_slice(&position.0);
210 key
211 }
212
213 pub(crate) fn parse_key(key: &[u8]) -> Result<(asset::Id, Amount, position::Id)> {
219 ensure!(key.len() == 125, "key must be 125 bytes");
220
221 let raw_asset: [u8; 32] = key[45..45 + 32].try_into()?;
223 let asset: asset::Id = raw_asset.try_into()?;
224
225 let raw_amount: [u8; 16] = key[45 + 32..45 + 32 + 16].try_into()?;
226 let amount_complement = Amount::from_be_bytes(raw_amount);
227 let amount = !amount_complement;
228
229 let raw_position_id: [u8; 32] =
230 key[45 + 32 + 16..45 + 32 + 16 + 32].try_into()?;
231 let position_id = position::Id(raw_position_id);
232
233 Ok((asset, amount, position_id))
234 }
235 }
236 }
237 }
238}
239
240pub(crate) mod engine {
241 use super::*;
242 use crate::lp::BareTradingFunction;
243
244 pub(crate) mod counter {
245 pub(crate) mod num_positions {
246 use crate::TradingPair;
247
248 pub(crate) fn prefix() -> &'static str {
249 "dex/internal/counter/num_positions/"
250 }
251
252 pub(crate) fn by_trading_pair(trading_pair: &TradingPair) -> [u8; 99] {
253 let mut key = [0u8; 99];
254 let prefix_bytes = prefix().as_bytes();
255 let canonical_pair_bytes = trading_pair.to_bytes();
256
257 key[0..35].copy_from_slice(prefix_bytes);
258 key[35..99].copy_from_slice(&canonical_pair_bytes);
259 key
260 }
261 }
262 }
263
264 pub(crate) mod routable_assets {
265 use penumbra_sdk_asset::asset;
266 use penumbra_sdk_num::Amount;
267
268 use super::*;
269
270 pub(crate) fn starting_from(from: &asset::Id) -> [u8; 39] {
276 let mut key = [0u8; 39];
277 key[0..7].copy_from_slice(b"dex/ra/");
278 key[7..39].copy_from_slice(&from.to_bytes());
279 key
280 }
281
282 pub(crate) fn key(from: &asset::Id, a_from_b: Amount) -> [u8; 55] {
288 let mut key = [0u8; 55];
289 key[0..7].copy_from_slice(b"dex/ra/");
290 key[7..32 + 7].copy_from_slice(&from.to_bytes());
291 key[32 + 7..32 + 7 + 16].copy_from_slice(&(!a_from_b).to_be_bytes());
293 key
294 }
295
296 pub(crate) fn lookup_base_liquidity_by_pair(pair: &DirectedTradingPair) -> [u8; 71] {
303 let mut key = [0u8; 71];
304 key[0..7].copy_from_slice(b"dex/ab/");
305 key[7..39].copy_from_slice(&pair.start.to_bytes());
306 key[39..71].copy_from_slice(&pair.end.to_bytes());
307 key
308 }
309 }
310
311 pub(crate) mod price_index {
312
313 use super::*;
314
315 pub(crate) fn prefix(pair: &DirectedTradingPair) -> [u8; 71] {
316 let mut key = [0u8; 71];
317 key[0..7].copy_from_slice(b"dex/pi/");
318 key[7..39].copy_from_slice(&pair.start.to_bytes());
319 key[39..71].copy_from_slice(&pair.end.to_bytes());
320 key
321 }
322
323 pub(crate) fn key(
324 pair: &DirectedTradingPair,
325 btf: &BareTradingFunction,
326 id: &position::Id,
327 ) -> Vec<u8> {
328 let id_bytes = id.0;
329 let mut key = [0u8; 135];
330 key[0..71].copy_from_slice(&prefix(pair));
331 key[71..103].copy_from_slice(&btf.effective_price_key_bytes());
332 key[103..135].copy_from_slice(&id_bytes);
333 key.to_vec()
334 }
335 }
336}
337
338pub(crate) mod eviction_queue {
339 pub(crate) mod inventory_index {
340 use crate::lp::position;
341 use crate::DirectedTradingPair;
342 use anyhow::ensure;
343 use penumbra_sdk_num::Amount;
344
345 pub(crate) fn by_trading_pair(pair: &DirectedTradingPair) -> [u8; 107] {
346 let mut prefix = [0u8; 107];
347 prefix[0..43].copy_from_slice(b"dex/internal/eviction_queue/inventory_index");
348 prefix[43..75].copy_from_slice(&pair.start.to_bytes());
349 prefix[75..107].copy_from_slice(&pair.end.to_bytes());
350 prefix
351 }
352
353 pub(crate) fn key(
354 pair: &DirectedTradingPair,
355 inventory: Amount,
356 id: &position::Id,
357 ) -> [u8; 155] {
358 let mut full_key = [0u8; 155];
359 let prefix = by_trading_pair(pair);
360 full_key[0..107].copy_from_slice(&prefix);
361 full_key[107..123].copy_from_slice(&inventory.to_be_bytes());
362 full_key[123..155].copy_from_slice(&id.0);
363
364 full_key
365 }
366
367 pub(crate) fn parse_id_from_key(key: Vec<u8>) -> anyhow::Result<[u8; 32]> {
368 ensure!(key.len() == 155, "key must be 155 bytes");
369 let k = &key[123..155];
370 Ok(k.try_into()?)
371 }
372 }
373}