1use crate::{
2 lp::position::{self, Position},
3 swap::Swap,
4 swap_claim::SwapClaim,
5 BatchSwapOutputData, CandlestickData, DirectedTradingPair, SwapExecution, TradingPair,
6};
7use anyhow::{anyhow, Context};
8use penumbra_sdk_asset::asset;
9use penumbra_sdk_num::Amount;
10use penumbra_sdk_proto::{penumbra::core::component::dex::v1 as pb, DomainType};
11use penumbra_sdk_sct::Nullifier;
12use penumbra_sdk_tct::StateCommitment;
13use prost::Name as _;
14
15#[derive(Clone, Debug)]
16pub struct EventSwap {
17 pub trading_pair: TradingPair,
18 pub delta_1_i: Amount,
19 pub delta_2_i: Amount,
20 pub swap_commitment: StateCommitment,
21}
22
23impl From<Swap> for EventSwap {
24 fn from(value: Swap) -> Self {
25 Self::from(&value)
26 }
27}
28
29impl From<&Swap> for EventSwap {
30 fn from(value: &Swap) -> Self {
31 Self {
32 trading_pair: value.body.trading_pair,
33 delta_1_i: value.body.delta_1_i,
34 delta_2_i: value.body.delta_2_i,
35 swap_commitment: value.body.payload.commitment,
36 }
37 }
38}
39
40impl TryFrom<pb::EventSwap> for EventSwap {
41 type Error = anyhow::Error;
42
43 fn try_from(value: pb::EventSwap) -> Result<Self, Self::Error> {
44 fn inner(value: pb::EventSwap) -> anyhow::Result<EventSwap> {
45 Ok(EventSwap {
46 trading_pair: value
47 .trading_pair
48 .ok_or(anyhow!("missing `trading_pair`"))?
49 .try_into()?,
50 delta_1_i: value
51 .delta_1_i
52 .ok_or(anyhow!("missing `delta_1_i`"))?
53 .try_into()?,
54 delta_2_i: value
55 .delta_2_i
56 .ok_or(anyhow!("missing `delta_2_i`"))?
57 .try_into()?,
58 swap_commitment: value
59 .swap_commitment
60 .ok_or(anyhow!("missing `swap_commitment`"))?
61 .try_into()?,
62 })
63 }
64 inner(value).context(format!("parsing {}", pb::EventSwap::NAME))
65 }
66}
67
68impl From<EventSwap> for pb::EventSwap {
69 fn from(value: EventSwap) -> Self {
70 Self {
71 trading_pair: Some(value.trading_pair.into()),
72 delta_1_i: Some(value.delta_1_i.into()),
73 delta_2_i: Some(value.delta_2_i.into()),
74 swap_commitment: Some(value.swap_commitment.into()),
75 }
76 }
77}
78
79impl DomainType for EventSwap {
80 type Proto = pb::EventSwap;
81}
82
83#[derive(Clone, Debug)]
84pub struct EventSwapClaim {
85 pub trading_pair: TradingPair,
86 pub output_1_commitment: StateCommitment,
87 pub output_2_commitment: StateCommitment,
88 pub nullifier: Nullifier,
89}
90
91impl From<SwapClaim> for EventSwapClaim {
92 fn from(value: SwapClaim) -> Self {
93 Self::from(&value)
94 }
95}
96
97impl From<&SwapClaim> for EventSwapClaim {
98 fn from(value: &SwapClaim) -> Self {
99 Self {
100 trading_pair: value.body.output_data.trading_pair,
101 output_1_commitment: value.body.output_1_commitment,
102 output_2_commitment: value.body.output_2_commitment,
103 nullifier: value.body.nullifier,
104 }
105 }
106}
107
108impl TryFrom<pb::EventSwapClaim> for EventSwapClaim {
109 type Error = anyhow::Error;
110
111 fn try_from(value: pb::EventSwapClaim) -> Result<Self, Self::Error> {
112 fn inner(value: pb::EventSwapClaim) -> anyhow::Result<EventSwapClaim> {
113 Ok(EventSwapClaim {
114 trading_pair: value
115 .trading_pair
116 .ok_or(anyhow!("missing `trading_pair`"))?
117 .try_into()?,
118 output_1_commitment: value
119 .output_1_commitment
120 .ok_or(anyhow!("missing `output_1_commitment`"))?
121 .try_into()?,
122 output_2_commitment: value
123 .output_2_commitment
124 .ok_or(anyhow!("missing `output_2_commitment`"))?
125 .try_into()?,
126 nullifier: value
127 .nullifier
128 .ok_or(anyhow!("missing `nullifier`"))?
129 .try_into()?,
130 })
131 }
132 inner(value).context(format!("parsing {}", pb::EventSwapClaim::NAME))
133 }
134}
135
136impl From<EventSwapClaim> for pb::EventSwapClaim {
137 fn from(value: EventSwapClaim) -> Self {
138 Self {
139 trading_pair: Some(value.trading_pair.into()),
140 output_1_commitment: Some(value.output_1_commitment.into()),
141 output_2_commitment: Some(value.output_2_commitment.into()),
142 nullifier: Some(value.nullifier.into()),
143 }
144 }
145}
146
147impl DomainType for EventSwapClaim {
148 type Proto = pb::EventSwapClaim;
149}
150
151#[derive(Clone, Debug)]
152pub struct EventPositionOpen {
153 pub position_id: position::Id,
154 pub trading_pair: TradingPair,
155 pub reserves_1: Amount,
156 pub reserves_2: Amount,
157 pub trading_fee: u32,
158 pub position: Position,
159}
160
161impl From<Position> for EventPositionOpen {
162 fn from(value: Position) -> Self {
163 Self {
164 position_id: value.id(),
165 trading_pair: value.phi.pair,
166 reserves_1: value.reserves_1().amount,
167 reserves_2: value.reserves_2().amount,
168 trading_fee: value.phi.component.fee,
169 position: value,
170 }
171 }
172}
173
174impl TryFrom<pb::EventPositionOpen> for EventPositionOpen {
175 type Error = anyhow::Error;
176
177 fn try_from(value: pb::EventPositionOpen) -> Result<Self, Self::Error> {
178 fn inner(value: pb::EventPositionOpen) -> anyhow::Result<EventPositionOpen> {
179 Ok(EventPositionOpen {
180 position_id: value
181 .position_id
182 .ok_or(anyhow!("missing `position_id`"))?
183 .try_into()?,
184 trading_pair: value
185 .trading_pair
186 .ok_or(anyhow!("missing `trading_pair`"))?
187 .try_into()?,
188 reserves_1: value
189 .reserves_1
190 .ok_or(anyhow!("missing `reserves_1`"))?
191 .try_into()?,
192 reserves_2: value
193 .reserves_2
194 .ok_or(anyhow!("missing `reserves_2`"))?
195 .try_into()?,
196 trading_fee: value.trading_fee,
197 position: value
198 .position
199 .ok_or(anyhow!("missing `position`"))?
200 .try_into()?,
201 })
202 }
203 inner(value).context(format!("parsing {}", pb::EventPositionOpen::NAME))
204 }
205}
206
207impl From<EventPositionOpen> for pb::EventPositionOpen {
208 fn from(value: EventPositionOpen) -> Self {
209 Self {
210 position_id: Some(value.position_id.into()),
211 trading_pair: Some(value.trading_pair.into()),
212 reserves_1: Some(value.reserves_1.into()),
213 reserves_2: Some(value.reserves_2.into()),
214 trading_fee: value.trading_fee,
215 position: Some(value.position.into()),
216 }
217 }
218}
219
220impl DomainType for EventPositionOpen {
221 type Proto = pb::EventPositionOpen;
222}
223
224#[derive(Clone, Debug)]
225pub struct EventPositionClose {
226 pub position_id: position::Id,
227}
228
229impl TryFrom<pb::EventPositionClose> for EventPositionClose {
230 type Error = anyhow::Error;
231
232 fn try_from(value: pb::EventPositionClose) -> Result<Self, Self::Error> {
233 fn inner(value: pb::EventPositionClose) -> anyhow::Result<EventPositionClose> {
234 Ok(EventPositionClose {
235 position_id: value
236 .position_id
237 .ok_or(anyhow!("missing `position_id`"))?
238 .try_into()?,
239 })
240 }
241 inner(value).context(format!("parsing {}", pb::EventPositionClose::NAME))
242 }
243}
244
245impl From<EventPositionClose> for pb::EventPositionClose {
246 fn from(value: EventPositionClose) -> Self {
247 Self {
248 position_id: Some(value.position_id.into()),
249 }
250 }
251}
252
253impl DomainType for EventPositionClose {
254 type Proto = pb::EventPositionClose;
255}
256
257#[derive(Clone, Debug)]
258pub struct EventQueuePositionClose {
259 pub position_id: position::Id,
260}
261
262impl TryFrom<pb::EventQueuePositionClose> for EventQueuePositionClose {
263 type Error = anyhow::Error;
264
265 fn try_from(value: pb::EventQueuePositionClose) -> Result<Self, Self::Error> {
266 fn inner(value: pb::EventQueuePositionClose) -> anyhow::Result<EventQueuePositionClose> {
267 Ok(EventQueuePositionClose {
268 position_id: value
269 .position_id
270 .ok_or(anyhow!("missing `position_id`"))?
271 .try_into()?,
272 })
273 }
274 inner(value).context(format!("parsing {}", pb::EventQueuePositionClose::NAME))
275 }
276}
277
278impl From<EventQueuePositionClose> for pb::EventQueuePositionClose {
279 fn from(value: EventQueuePositionClose) -> Self {
280 Self {
281 position_id: Some(value.position_id.into()),
282 }
283 }
284}
285
286impl DomainType for EventQueuePositionClose {
287 type Proto = pb::EventQueuePositionClose;
288}
289
290#[derive(Clone, Debug)]
291pub struct EventPositionWithdraw {
292 pub position_id: position::Id,
293 pub trading_pair: TradingPair,
294 pub reserves_1: Amount,
295 pub reserves_2: Amount,
296 pub sequence: u64,
297}
298
299impl EventPositionWithdraw {
300 pub fn in_context(position_id: position::Id, final_position_state: &Position) -> Self {
302 let sequence =
303 if let position::State::Withdrawn { sequence, .. } = final_position_state.state {
304 sequence + 1
305 } else {
306 0
307 };
308 Self {
309 position_id,
310 trading_pair: final_position_state.phi.pair,
311 reserves_1: final_position_state.reserves.r1,
312 reserves_2: final_position_state.reserves.r2,
313 sequence,
314 }
315 }
316}
317
318impl TryFrom<pb::EventPositionWithdraw> for EventPositionWithdraw {
319 type Error = anyhow::Error;
320
321 fn try_from(value: pb::EventPositionWithdraw) -> Result<Self, Self::Error> {
322 fn inner(value: pb::EventPositionWithdraw) -> anyhow::Result<EventPositionWithdraw> {
323 Ok(EventPositionWithdraw {
324 position_id: value
325 .position_id
326 .ok_or(anyhow!("missing `position_id`"))?
327 .try_into()?,
328 trading_pair: value
329 .trading_pair
330 .ok_or(anyhow!("missing `trading_pair`"))?
331 .try_into()?,
332 reserves_1: value
333 .reserves_1
334 .ok_or(anyhow!("missing `reserves_1`"))?
335 .try_into()?,
336 reserves_2: value
337 .reserves_2
338 .ok_or(anyhow!("missing `reserves_2`"))?
339 .try_into()?,
340 sequence: value.sequence,
341 })
342 }
343 inner(value).context(format!("parsing {}", pb::EventPositionWithdraw::NAME))
344 }
345}
346
347impl From<EventPositionWithdraw> for pb::EventPositionWithdraw {
348 fn from(value: EventPositionWithdraw) -> Self {
349 Self {
350 position_id: Some(value.position_id.into()),
351 trading_pair: Some(value.trading_pair.into()),
352 reserves_1: Some(value.reserves_1.into()),
353 reserves_2: Some(value.reserves_2.into()),
354 sequence: value.sequence,
355 }
356 }
357}
358
359impl DomainType for EventPositionWithdraw {
360 type Proto = pb::EventPositionWithdraw;
361}
362
363#[derive(Clone, Debug)]
364pub struct EventPositionExecution {
365 pub position_id: position::Id,
366 pub trading_pair: TradingPair,
367 pub reserves_1: Amount,
368 pub reserves_2: Amount,
369 pub prev_reserves_1: Amount,
370 pub prev_reserves_2: Amount,
371 pub context: DirectedTradingPair,
372}
373
374impl EventPositionExecution {
375 pub fn in_context(
377 prev_state: &Position,
378 new_state: &Position,
379 context: DirectedTradingPair,
380 ) -> Self {
381 Self {
382 position_id: new_state.id(),
383 trading_pair: new_state.phi.pair,
384 reserves_1: new_state.reserves_1().amount,
385 reserves_2: new_state.reserves_2().amount,
386 prev_reserves_1: prev_state.reserves_1().amount,
387 prev_reserves_2: prev_state.reserves_2().amount,
388 context,
389 }
390 }
391}
392
393impl TryFrom<pb::EventPositionExecution> for EventPositionExecution {
394 type Error = anyhow::Error;
395
396 fn try_from(value: pb::EventPositionExecution) -> Result<Self, Self::Error> {
397 fn inner(value: pb::EventPositionExecution) -> anyhow::Result<EventPositionExecution> {
398 Ok(EventPositionExecution {
399 position_id: value
400 .position_id
401 .ok_or(anyhow!("missing `position_id`"))?
402 .try_into()?,
403 trading_pair: value
404 .trading_pair
405 .ok_or(anyhow!("missing `trading_pair`"))?
406 .try_into()?,
407 reserves_1: value
408 .reserves_1
409 .ok_or(anyhow!("missing `reserves_1`"))?
410 .try_into()?,
411 reserves_2: value
412 .reserves_2
413 .ok_or(anyhow!("missing `reserves_2`"))?
414 .try_into()?,
415 prev_reserves_1: value
416 .prev_reserves_1
417 .ok_or(anyhow!("missing `prev_reserves_1`"))?
418 .try_into()?,
419 prev_reserves_2: value
420 .prev_reserves_2
421 .ok_or(anyhow!("missing `prev_reserves_2`"))?
422 .try_into()?,
423 context: value
424 .context
425 .ok_or(anyhow!("missing `context`"))?
426 .try_into()?,
427 })
428 }
429 inner(value).context(format!("parsing {}", pb::EventPositionExecution::NAME))
430 }
431}
432
433impl From<EventPositionExecution> for pb::EventPositionExecution {
434 fn from(value: EventPositionExecution) -> Self {
435 Self {
436 position_id: Some(value.position_id.into()),
437 trading_pair: Some(value.trading_pair.into()),
438 reserves_1: Some(value.reserves_1.into()),
439 reserves_2: Some(value.reserves_2.into()),
440 prev_reserves_1: Some(value.prev_reserves_1.into()),
441 prev_reserves_2: Some(value.prev_reserves_2.into()),
442 context: Some(value.context.into()),
443 }
444 }
445}
446
447impl DomainType for EventPositionExecution {
448 type Proto = pb::EventPositionExecution;
449}
450
451#[derive(Clone, Debug)]
452pub struct EventBatchSwap {
453 pub batch_swap_output_data: BatchSwapOutputData,
454 pub swap_execution_1_for_2: Option<SwapExecution>,
455 pub swap_execution_2_for_1: Option<SwapExecution>,
456}
457
458impl TryFrom<pb::EventBatchSwap> for EventBatchSwap {
459 type Error = anyhow::Error;
460
461 fn try_from(value: pb::EventBatchSwap) -> Result<Self, Self::Error> {
462 fn inner(value: pb::EventBatchSwap) -> anyhow::Result<EventBatchSwap> {
463 Ok(EventBatchSwap {
464 batch_swap_output_data: value
465 .batch_swap_output_data
466 .ok_or(anyhow!("missing `batch_swap_output_data`"))?
467 .try_into()?,
468 swap_execution_1_for_2: value
469 .swap_execution_1_for_2
470 .map(|x| x.try_into())
471 .transpose()?,
472 swap_execution_2_for_1: value
473 .swap_execution_2_for_1
474 .map(|x| x.try_into())
475 .transpose()?,
476 })
477 }
478 inner(value).context(format!("parsing {}", pb::EventBatchSwap::NAME))
479 }
480}
481
482impl From<EventBatchSwap> for pb::EventBatchSwap {
483 fn from(value: EventBatchSwap) -> Self {
484 Self {
485 batch_swap_output_data: Some(value.batch_swap_output_data.into()),
486 swap_execution_1_for_2: value.swap_execution_1_for_2.map(|x| x.into()),
487 swap_execution_2_for_1: value.swap_execution_2_for_1.map(|x| x.into()),
488 }
489 }
490}
491
492impl DomainType for EventBatchSwap {
493 type Proto = pb::EventBatchSwap;
494}
495
496#[derive(Clone, Debug)]
497pub struct EventArbExecution {
498 pub height: u64,
499 pub swap_execution: SwapExecution,
500}
501
502impl TryFrom<pb::EventArbExecution> for EventArbExecution {
503 type Error = anyhow::Error;
504
505 fn try_from(value: pb::EventArbExecution) -> Result<Self, Self::Error> {
506 fn inner(value: pb::EventArbExecution) -> anyhow::Result<EventArbExecution> {
507 Ok(EventArbExecution {
508 height: value.height,
509 swap_execution: value
510 .swap_execution
511 .ok_or(anyhow!("missing `swap_execution`"))?
512 .try_into()?,
513 })
514 }
515 inner(value).context(format!("parsing {}", pb::EventArbExecution::NAME))
516 }
517}
518
519impl From<EventArbExecution> for pb::EventArbExecution {
520 fn from(value: EventArbExecution) -> Self {
521 Self {
522 height: value.height,
523 swap_execution: Some(value.swap_execution.into()),
524 }
525 }
526}
527
528impl DomainType for EventArbExecution {
529 type Proto = pb::EventArbExecution;
530}
531
532#[derive(Clone, Debug)]
533pub struct EventValueCircuitBreakerCredit {
534 pub asset_id: asset::Id,
535 pub previous_balance: Amount,
536 pub new_balance: Amount,
537}
538
539impl TryFrom<pb::EventValueCircuitBreakerCredit> for EventValueCircuitBreakerCredit {
540 type Error = anyhow::Error;
541
542 fn try_from(value: pb::EventValueCircuitBreakerCredit) -> Result<Self, Self::Error> {
543 fn inner(
544 value: pb::EventValueCircuitBreakerCredit,
545 ) -> anyhow::Result<EventValueCircuitBreakerCredit> {
546 Ok(EventValueCircuitBreakerCredit {
547 asset_id: value
548 .asset_id
549 .ok_or(anyhow!("missing `asset_id`"))?
550 .try_into()?,
551 previous_balance: value
552 .previous_balance
553 .ok_or(anyhow!("missing `previous_balance`"))?
554 .try_into()?,
555 new_balance: value
556 .new_balance
557 .ok_or(anyhow!("missing `new_balance`"))?
558 .try_into()?,
559 })
560 }
561 inner(value).context(format!(
562 "parsing {}",
563 pb::EventValueCircuitBreakerCredit::NAME
564 ))
565 }
566}
567
568impl From<EventValueCircuitBreakerCredit> for pb::EventValueCircuitBreakerCredit {
569 fn from(value: EventValueCircuitBreakerCredit) -> Self {
570 Self {
571 asset_id: Some(value.asset_id.into()),
572 previous_balance: Some(value.previous_balance.into()),
573 new_balance: Some(value.new_balance.into()),
574 }
575 }
576}
577
578impl DomainType for EventValueCircuitBreakerCredit {
579 type Proto = pb::EventValueCircuitBreakerCredit;
580}
581
582#[derive(Clone, Debug)]
583pub struct EventValueCircuitBreakerDebit {
584 pub asset_id: asset::Id,
585 pub previous_balance: Amount,
586 pub new_balance: Amount,
587}
588
589impl TryFrom<pb::EventValueCircuitBreakerDebit> for EventValueCircuitBreakerDebit {
590 type Error = anyhow::Error;
591
592 fn try_from(value: pb::EventValueCircuitBreakerDebit) -> Result<Self, Self::Error> {
593 fn inner(
594 value: pb::EventValueCircuitBreakerDebit,
595 ) -> anyhow::Result<EventValueCircuitBreakerDebit> {
596 Ok(EventValueCircuitBreakerDebit {
597 asset_id: value
598 .asset_id
599 .ok_or(anyhow!("missing `asset_id`"))?
600 .try_into()?,
601 previous_balance: value
602 .previous_balance
603 .ok_or(anyhow!("missing `previous_balance`"))?
604 .try_into()?,
605 new_balance: value
606 .new_balance
607 .ok_or(anyhow!("missing `new_balance`"))?
608 .try_into()?,
609 })
610 }
611 inner(value).context(format!(
612 "parsing {}",
613 pb::EventValueCircuitBreakerDebit::NAME
614 ))
615 }
616}
617
618impl From<EventValueCircuitBreakerDebit> for pb::EventValueCircuitBreakerDebit {
619 fn from(value: EventValueCircuitBreakerDebit) -> Self {
620 Self {
621 asset_id: Some(value.asset_id.into()),
622 previous_balance: Some(value.previous_balance.into()),
623 new_balance: Some(value.new_balance.into()),
624 }
625 }
626}
627
628impl DomainType for EventValueCircuitBreakerDebit {
629 type Proto = pb::EventValueCircuitBreakerDebit;
630}
631
632#[derive(Clone, Debug)]
633pub struct EventCandlestickData {
634 pub pair: DirectedTradingPair,
635 pub stick: CandlestickData,
636}
637
638impl TryFrom<pb::EventCandlestickData> for EventCandlestickData {
639 type Error = anyhow::Error;
640
641 fn try_from(value: pb::EventCandlestickData) -> Result<Self, Self::Error> {
642 fn inner(value: pb::EventCandlestickData) -> anyhow::Result<EventCandlestickData> {
643 Ok(EventCandlestickData {
644 pair: value.pair.ok_or(anyhow!("missing `pair`"))?.try_into()?,
645 stick: value.stick.ok_or(anyhow!("missing `stick`"))?.try_into()?,
646 })
647 }
648 inner(value).context(format!("parsing {}", pb::EventCandlestickData::NAME))
649 }
650}
651
652impl From<EventCandlestickData> for pb::EventCandlestickData {
653 fn from(value: EventCandlestickData) -> Self {
654 Self {
655 pair: Some(value.pair.into()),
656 stick: Some(value.stick.into()),
657 }
658 }
659}
660
661impl DomainType for EventCandlestickData {
662 type Proto = pb::EventCandlestickData;
663}