1use crate::abi::tongo_events;
4use crate::types::{AEBalance, CipherBalance};
5use krusty_kms_common::{KmsError, Result};
6use starknet_rust::core::types::{BlockId, BlockTag, EmittedEvent, EventFilter};
7use starknet_rust::providers::jsonrpc::{HttpTransport, JsonRpcClient};
8use starknet_rust::providers::Provider;
9use starknet_types_core::curve::ProjectivePoint;
10use starknet_types_core::felt::Felt as CoreFelt;
11use std::sync::Arc;
12
13type StarknetRsFelt = starknet_rust::core::types::Felt;
14
15fn rs_felt_to_core(felt: StarknetRsFelt) -> CoreFelt {
16 CoreFelt::from_bytes_be(&felt.to_bytes_be())
17}
18
19fn core_felt_to_rs(felt: CoreFelt) -> StarknetRsFelt {
20 StarknetRsFelt::from_bytes_be(&felt.to_bytes_be())
21}
22
23#[derive(Debug, Clone)]
26pub struct EventMetadata {
27 pub block_number: Option<u64>,
28 pub tx_hash: StarknetRsFelt,
29}
30
31fn meta(e: &EmittedEvent) -> EventMetadata {
32 EventMetadata {
33 block_number: e.block_number,
34 tx_hash: e.transaction_hash,
35 }
36}
37
38#[derive(Debug, Clone)]
41pub struct FundEvent {
42 pub meta: EventMetadata,
43 pub to: ProjectivePoint,
44 pub nonce: u64,
45 pub from: CoreFelt,
46 pub amount: u128,
47}
48
49#[derive(Debug, Clone)]
50pub struct OutsideFundEvent {
51 pub meta: EventMetadata,
52 pub to: ProjectivePoint,
53 pub from: CoreFelt,
54 pub amount: u128,
55}
56
57#[derive(Debug, Clone)]
58pub struct WithdrawEvent {
59 pub meta: EventMetadata,
60 pub from: ProjectivePoint,
61 pub nonce: u64,
62 pub amount: u128,
63 pub to: CoreFelt,
64}
65
66#[derive(Debug, Clone)]
67pub struct RagequitEvent {
68 pub meta: EventMetadata,
69 pub from: ProjectivePoint,
70 pub nonce: u64,
71 pub amount: u128,
72 pub to: CoreFelt,
73}
74
75#[derive(Debug, Clone)]
76pub struct RolloverEvent {
77 pub meta: EventMetadata,
78 pub to: ProjectivePoint,
79 pub nonce: u64,
80 pub rollovered: CipherBalance,
81}
82
83#[derive(Debug, Clone)]
84pub struct TransferEvent {
85 pub meta: EventMetadata,
86 pub to: ProjectivePoint,
87 pub from: ProjectivePoint,
88 pub nonce: u64,
89 pub transfer_balance: CipherBalance,
90 pub transfer_balance_self: CipherBalance,
91 pub hint_transfer: AEBalance,
92 pub hint_leftover: AEBalance,
93}
94
95#[derive(Debug, Clone)]
96pub struct BalanceDeclaredEvent {
97 pub meta: EventMetadata,
98 pub from: ProjectivePoint,
99 pub nonce: u64,
100 pub auditor_pub_key: ProjectivePoint,
101 pub declared_cipher_balance: CipherBalance,
102 pub hint: AEBalance,
103}
104
105#[derive(Debug, Clone)]
106pub struct TransferDeclaredEvent {
107 pub meta: EventMetadata,
108 pub from: ProjectivePoint,
109 pub to: ProjectivePoint,
110 pub nonce: u64,
111 pub auditor_pub_key: ProjectivePoint,
112 pub declared_cipher_balance: CipherBalance,
113 pub hint: AEBalance,
114}
115
116#[derive(Debug, Clone)]
119pub enum TongoEvent {
120 Fund(FundEvent),
121 OutsideFund(OutsideFundEvent),
122 Withdraw(WithdrawEvent),
123 Ragequit(RagequitEvent),
124 Rollover(RolloverEvent),
125 Transfer(TransferEvent),
126 BalanceDeclared(BalanceDeclaredEvent),
127 TransferDeclared(TransferDeclaredEvent),
128}
129
130impl TongoEvent {
131 pub fn block_number(&self) -> Option<u64> {
132 match self {
133 Self::Fund(e) => e.meta.block_number,
134 Self::OutsideFund(e) => e.meta.block_number,
135 Self::Withdraw(e) => e.meta.block_number,
136 Self::Ragequit(e) => e.meta.block_number,
137 Self::Rollover(e) => e.meta.block_number,
138 Self::Transfer(e) => e.meta.block_number,
139 Self::BalanceDeclared(e) => e.meta.block_number,
140 Self::TransferDeclared(e) => e.meta.block_number,
141 }
142 }
143}
144
145fn parse_point(felts: &[StarknetRsFelt], offset: usize) -> Result<ProjectivePoint> {
148 if felts.len() < offset + 2 {
149 return Err(KmsError::DeserializationError(
150 "Not enough felts for point".to_string(),
151 ));
152 }
153 ProjectivePoint::from_affine(
154 rs_felt_to_core(felts[offset]),
155 rs_felt_to_core(felts[offset + 1]),
156 )
157 .map_err(|_| KmsError::DeserializationError("Invalid point in event data".to_string()))
158}
159
160fn parse_cipher_balance(felts: &[StarknetRsFelt], offset: usize) -> Result<CipherBalance> {
161 Ok(CipherBalance {
162 l: parse_point(felts, offset)?,
163 r: parse_point(felts, offset + 2)?,
164 })
165}
166
167fn felt_to_u128(felt: &StarknetRsFelt) -> u128 {
168 let bytes = felt.to_bytes_be();
169 let mut buf = [0u8; 16];
170 buf.copy_from_slice(&bytes[16..32]);
171 u128::from_be_bytes(buf)
172}
173
174fn felt_to_u64(felt: &StarknetRsFelt) -> u64 {
175 let bytes = felt.to_bytes_be();
176 let mut buf = [0u8; 8];
177 buf.copy_from_slice(&bytes[24..32]);
178 u64::from_be_bytes(buf)
179}
180
181fn get_felt(felts: &[StarknetRsFelt], index: usize) -> Result<&StarknetRsFelt> {
182 felts.get(index).ok_or_else(|| {
183 KmsError::DeserializationError(format!(
184 "Event data too short: need index {index}, got {} elements",
185 felts.len()
186 ))
187 })
188}
189
190fn parse_ae_balance(felts: &[StarknetRsFelt], offset: usize) -> Result<AEBalance> {
192 if felts.len() < offset + 6 {
193 return Err(KmsError::DeserializationError(
194 "Not enough felts for AEBalance".to_string(),
195 ));
196 }
197
198 let mut ciphertext = [0u8; 64];
200 for i in 0..4 {
201 let bytes = felts[offset + i].to_bytes_be();
202 ciphertext[i * 16..(i + 1) * 16].copy_from_slice(&bytes[16..32]);
203 }
204
205 let mut nonce = [0u8; 24];
207 let n0 = felts[offset + 4].to_bytes_be();
208 nonce[0..12].copy_from_slice(&n0[20..32]);
209 let n1 = felts[offset + 5].to_bytes_be();
210 nonce[12..24].copy_from_slice(&n1[20..32]);
211
212 Ok(AEBalance { ciphertext, nonce })
213}
214
215pub struct TongoEventReader {
219 provider: Arc<JsonRpcClient<HttpTransport>>,
220 contract_address: StarknetRsFelt,
221}
222
223impl TongoEventReader {
224 pub fn new(provider: Arc<JsonRpcClient<HttpTransport>>, contract_address: CoreFelt) -> Self {
225 Self {
226 provider,
227 contract_address: core_felt_to_rs(contract_address),
228 }
229 }
230
231 async fn fetch_events(
233 &self,
234 keys: Vec<Vec<StarknetRsFelt>>,
235 from_block: Option<u64>,
236 to_block: Option<u64>,
237 ) -> Result<Vec<EmittedEvent>> {
238 let filter = EventFilter {
239 from_block: from_block.map(BlockId::Number),
240 to_block: to_block
241 .map(BlockId::Number)
242 .or(Some(BlockId::Tag(BlockTag::Latest))),
243 address: Some(self.contract_address),
244 keys: Some(keys),
245 };
246
247 let mut all_events = Vec::new();
248 let mut continuation_token: Option<String> = None;
249
250 loop {
251 let page = self
252 .provider
253 .get_events(filter.clone(), continuation_token, 100)
254 .await
255 .map_err(|e| KmsError::RpcError(e.to_string()))?;
256
257 all_events.extend(page.events);
258
259 match page.continuation_token {
260 Some(token) => continuation_token = Some(token),
261 None => break,
262 }
263 }
264
265 Ok(all_events)
266 }
267
268 pub async fn get_fund_events(
272 &self,
273 pub_key: &ProjectivePoint,
274 from_block: Option<u64>,
275 to_block: Option<u64>,
276 ) -> Result<Vec<FundEvent>> {
277 let (kx, ky) = point_to_rs_felts(pub_key)?;
278 let keys = vec![vec![*tongo_events::FUND_EVENT], vec![kx], vec![ky]];
279 let raw = self.fetch_events(keys, from_block, to_block).await?;
280 raw.iter().map(parse_fund_event).collect()
281 }
282
283 pub async fn get_outside_fund_events(
285 &self,
286 pub_key: &ProjectivePoint,
287 from_block: Option<u64>,
288 to_block: Option<u64>,
289 ) -> Result<Vec<OutsideFundEvent>> {
290 let (kx, ky) = point_to_rs_felts(pub_key)?;
291 let keys = vec![vec![*tongo_events::OUTSIDE_FUND_EVENT], vec![kx], vec![ky]];
292 let raw = self.fetch_events(keys, from_block, to_block).await?;
293 raw.iter().map(parse_outside_fund_event).collect()
294 }
295
296 pub async fn get_withdraw_events(
298 &self,
299 pub_key: &ProjectivePoint,
300 from_block: Option<u64>,
301 to_block: Option<u64>,
302 ) -> Result<Vec<WithdrawEvent>> {
303 let (kx, ky) = point_to_rs_felts(pub_key)?;
304 let keys = vec![vec![*tongo_events::WITHDRAW_EVENT], vec![kx], vec![ky]];
305 let raw = self.fetch_events(keys, from_block, to_block).await?;
306 raw.iter().map(parse_withdraw_event).collect()
307 }
308
309 pub async fn get_ragequit_events(
311 &self,
312 pub_key: &ProjectivePoint,
313 from_block: Option<u64>,
314 to_block: Option<u64>,
315 ) -> Result<Vec<RagequitEvent>> {
316 let (kx, ky) = point_to_rs_felts(pub_key)?;
317 let keys = vec![vec![*tongo_events::RAGEQUIT_EVENT], vec![kx], vec![ky]];
318 let raw = self.fetch_events(keys, from_block, to_block).await?;
319 raw.iter().map(parse_ragequit_event).collect()
320 }
321
322 pub async fn get_rollover_events(
324 &self,
325 pub_key: &ProjectivePoint,
326 from_block: Option<u64>,
327 to_block: Option<u64>,
328 ) -> Result<Vec<RolloverEvent>> {
329 let (kx, ky) = point_to_rs_felts(pub_key)?;
330 let keys = vec![vec![*tongo_events::ROLLOVER_EVENT], vec![kx], vec![ky]];
331 let raw = self.fetch_events(keys, from_block, to_block).await?;
332 raw.iter().map(parse_rollover_event).collect()
333 }
334
335 pub async fn get_transfer_in_events(
337 &self,
338 pub_key: &ProjectivePoint,
339 from_block: Option<u64>,
340 to_block: Option<u64>,
341 ) -> Result<Vec<TransferEvent>> {
342 let (kx, ky) = point_to_rs_felts(pub_key)?;
343 let keys = vec![vec![*tongo_events::TRANSFER_EVENT], vec![kx], vec![ky]];
344 let raw = self.fetch_events(keys, from_block, to_block).await?;
345 raw.iter().map(parse_transfer_event).collect()
346 }
347
348 pub async fn get_transfer_out_events(
350 &self,
351 pub_key: &ProjectivePoint,
352 from_block: Option<u64>,
353 to_block: Option<u64>,
354 ) -> Result<Vec<TransferEvent>> {
355 let (kx, ky) = point_to_rs_felts(pub_key)?;
356 let keys = vec![
358 vec![*tongo_events::TRANSFER_EVENT],
359 vec![],
360 vec![],
361 vec![kx],
362 vec![ky],
363 ];
364 let raw = self.fetch_events(keys, from_block, to_block).await?;
365 raw.iter().map(parse_transfer_event).collect()
366 }
367
368 pub async fn get_balance_declared_events(
370 &self,
371 pub_key: &ProjectivePoint,
372 from_block: Option<u64>,
373 to_block: Option<u64>,
374 ) -> Result<Vec<BalanceDeclaredEvent>> {
375 let (kx, ky) = point_to_rs_felts(pub_key)?;
376 let keys = vec![
377 vec![*tongo_events::BALANCE_DECLARED_EVENT],
378 vec![kx],
379 vec![ky],
380 ];
381 let raw = self.fetch_events(keys, from_block, to_block).await?;
382 raw.iter().map(parse_balance_declared_event).collect()
383 }
384
385 pub async fn get_transfer_declared_from_events(
387 &self,
388 pub_key: &ProjectivePoint,
389 from_block: Option<u64>,
390 to_block: Option<u64>,
391 ) -> Result<Vec<TransferDeclaredEvent>> {
392 let (kx, ky) = point_to_rs_felts(pub_key)?;
393 let keys = vec![
394 vec![*tongo_events::TRANSFER_DECLARED_EVENT],
395 vec![kx],
396 vec![ky],
397 ];
398 let raw = self.fetch_events(keys, from_block, to_block).await?;
399 raw.iter().map(parse_transfer_declared_event).collect()
400 }
401
402 pub async fn get_transfer_declared_to_events(
404 &self,
405 pub_key: &ProjectivePoint,
406 from_block: Option<u64>,
407 to_block: Option<u64>,
408 ) -> Result<Vec<TransferDeclaredEvent>> {
409 let (kx, ky) = point_to_rs_felts(pub_key)?;
410 let keys = vec![
411 vec![*tongo_events::TRANSFER_DECLARED_EVENT],
412 vec![],
413 vec![],
414 vec![kx],
415 vec![ky],
416 ];
417 let raw = self.fetch_events(keys, from_block, to_block).await?;
418 raw.iter().map(parse_transfer_declared_event).collect()
419 }
420
421 pub async fn get_all_events(
423 &self,
424 pub_key: &ProjectivePoint,
425 from_block: Option<u64>,
426 to_block: Option<u64>,
427 ) -> Result<Vec<TongoEvent>> {
428 let (
429 fund,
430 outside_fund,
431 withdraw,
432 ragequit,
433 rollover,
434 transfer_in,
435 transfer_out,
436 balance_declared,
437 transfer_declared_from,
438 transfer_declared_to,
439 ) = tokio::join!(
440 self.get_fund_events(pub_key, from_block, to_block),
441 self.get_outside_fund_events(pub_key, from_block, to_block),
442 self.get_withdraw_events(pub_key, from_block, to_block),
443 self.get_ragequit_events(pub_key, from_block, to_block),
444 self.get_rollover_events(pub_key, from_block, to_block),
445 self.get_transfer_in_events(pub_key, from_block, to_block),
446 self.get_transfer_out_events(pub_key, from_block, to_block),
447 self.get_balance_declared_events(pub_key, from_block, to_block),
448 self.get_transfer_declared_from_events(pub_key, from_block, to_block),
449 self.get_transfer_declared_to_events(pub_key, from_block, to_block),
450 );
451
452 let mut all: Vec<TongoEvent> = Vec::new();
453
454 for e in fund? {
455 all.push(TongoEvent::Fund(e));
456 }
457 for e in outside_fund? {
458 all.push(TongoEvent::OutsideFund(e));
459 }
460 for e in withdraw? {
461 all.push(TongoEvent::Withdraw(e));
462 }
463 for e in ragequit? {
464 all.push(TongoEvent::Ragequit(e));
465 }
466 for e in rollover? {
467 all.push(TongoEvent::Rollover(e));
468 }
469 for e in transfer_in? {
470 all.push(TongoEvent::Transfer(e));
471 }
472 for e in transfer_out? {
473 all.push(TongoEvent::Transfer(e));
474 }
475 for e in balance_declared? {
476 all.push(TongoEvent::BalanceDeclared(e));
477 }
478 for e in transfer_declared_from? {
479 all.push(TongoEvent::TransferDeclared(e));
480 }
481 for e in transfer_declared_to? {
482 all.push(TongoEvent::TransferDeclared(e));
483 }
484
485 all.sort_by_key(|e| std::cmp::Reverse(e.block_number()));
487
488 Ok(all)
489 }
490}
491
492fn point_to_rs_felts(point: &ProjectivePoint) -> Result<(StarknetRsFelt, StarknetRsFelt)> {
495 let affine = point
496 .to_affine()
497 .map_err(|_| KmsError::CryptoError("Invalid public key".to_string()))?;
498 Ok((core_felt_to_rs(affine.x()), core_felt_to_rs(affine.y())))
499}
500
501fn parse_fund_event(e: &EmittedEvent) -> Result<FundEvent> {
504 let to = parse_point(&e.keys, 1)?;
507 Ok(FundEvent {
508 meta: meta(e),
509 to,
510 nonce: felt_to_u64(get_felt(&e.data, 0)?),
511 from: rs_felt_to_core(*get_felt(&e.data, 1)?),
512 amount: felt_to_u128(get_felt(&e.data, 2)?),
513 })
514}
515
516fn parse_outside_fund_event(e: &EmittedEvent) -> Result<OutsideFundEvent> {
517 let to = parse_point(&e.keys, 1)?;
520 Ok(OutsideFundEvent {
521 meta: meta(e),
522 to,
523 from: rs_felt_to_core(*get_felt(&e.data, 0)?),
524 amount: felt_to_u128(get_felt(&e.data, 1)?),
525 })
526}
527
528fn parse_withdraw_event(e: &EmittedEvent) -> Result<WithdrawEvent> {
529 let from = parse_point(&e.keys, 1)?;
532 Ok(WithdrawEvent {
533 meta: meta(e),
534 from,
535 nonce: felt_to_u64(get_felt(&e.data, 0)?),
536 amount: felt_to_u128(get_felt(&e.data, 1)?),
537 to: rs_felt_to_core(*get_felt(&e.data, 2)?),
538 })
539}
540
541fn parse_ragequit_event(e: &EmittedEvent) -> Result<RagequitEvent> {
542 let from = parse_point(&e.keys, 1)?;
545 Ok(RagequitEvent {
546 meta: meta(e),
547 from,
548 nonce: felt_to_u64(get_felt(&e.data, 0)?),
549 amount: felt_to_u128(get_felt(&e.data, 1)?),
550 to: rs_felt_to_core(*get_felt(&e.data, 2)?),
551 })
552}
553
554fn parse_rollover_event(e: &EmittedEvent) -> Result<RolloverEvent> {
555 let to = parse_point(&e.keys, 1)?;
558 Ok(RolloverEvent {
559 meta: meta(e),
560 to,
561 nonce: felt_to_u64(get_felt(&e.data, 0)?),
562 rollovered: parse_cipher_balance(&e.data, 1)?,
563 })
564}
565
566fn parse_transfer_event(e: &EmittedEvent) -> Result<TransferEvent> {
567 let to = parse_point(&e.keys, 1)?;
570 let from = parse_point(&e.keys, 3)?;
571 Ok(TransferEvent {
572 meta: meta(e),
573 to,
574 from,
575 nonce: felt_to_u64(get_felt(&e.data, 0)?),
576 transfer_balance: parse_cipher_balance(&e.data, 1)?,
577 transfer_balance_self: parse_cipher_balance(&e.data, 5)?,
578 hint_transfer: parse_ae_balance(&e.data, 9)?,
579 hint_leftover: parse_ae_balance(&e.data, 15)?,
580 })
581}
582
583fn parse_balance_declared_event(e: &EmittedEvent) -> Result<BalanceDeclaredEvent> {
584 let from = parse_point(&e.keys, 1)?;
587 Ok(BalanceDeclaredEvent {
588 meta: meta(e),
589 from,
590 nonce: felt_to_u64(get_felt(&e.data, 0)?),
591 auditor_pub_key: parse_point(&e.data, 1)?,
592 declared_cipher_balance: parse_cipher_balance(&e.data, 3)?,
593 hint: parse_ae_balance(&e.data, 7)?,
594 })
595}
596
597fn parse_transfer_declared_event(e: &EmittedEvent) -> Result<TransferDeclaredEvent> {
598 let from = parse_point(&e.keys, 1)?;
601 let to = parse_point(&e.keys, 3)?;
602 Ok(TransferDeclaredEvent {
603 meta: meta(e),
604 from,
605 to,
606 nonce: felt_to_u64(get_felt(&e.data, 0)?),
607 auditor_pub_key: parse_point(&e.data, 1)?,
608 declared_cipher_balance: parse_cipher_balance(&e.data, 3)?,
609 hint: parse_ae_balance(&e.data, 7)?,
610 })
611}
612
613#[cfg(test)]
614mod tests {
615 use super::*;
616
617 fn make_felt(v: u64) -> StarknetRsFelt {
618 StarknetRsFelt::from(v)
619 }
620
621 fn generator_rs() -> (StarknetRsFelt, StarknetRsFelt) {
622 let g_x = StarknetRsFelt::from_hex(
623 "0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca",
624 )
625 .unwrap();
626 let g_y = StarknetRsFelt::from_hex(
627 "0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f",
628 )
629 .unwrap();
630 (g_x, g_y)
631 }
632
633 #[test]
634 fn test_parse_fund_event() {
635 let (gx, gy) = generator_rs();
636 let event = EmittedEvent {
637 from_address: make_felt(0x999),
638 keys: vec![*tongo_events::FUND_EVENT, gx, gy],
639 data: vec![make_felt(1), make_felt(0xABC), make_felt(500)],
640 block_hash: None,
641 block_number: Some(100),
642 transaction_hash: make_felt(0xDEAD),
643 event_index: 0,
644 transaction_index: 0,
645 };
646
647 let parsed = parse_fund_event(&event).unwrap();
648 assert_eq!(parsed.nonce, 1);
649 assert_eq!(parsed.amount, 500);
650 assert_eq!(parsed.meta.block_number, Some(100));
651 }
652
653 #[test]
654 fn test_parse_outside_fund_event() {
655 let (gx, gy) = generator_rs();
656 let event = EmittedEvent {
657 from_address: make_felt(0x999),
658 keys: vec![*tongo_events::OUTSIDE_FUND_EVENT, gx, gy],
659 data: vec![make_felt(0xABC), make_felt(1000)],
660 block_hash: None,
661 block_number: Some(200),
662 transaction_hash: make_felt(0xBEEF),
663 event_index: 0,
664 transaction_index: 0,
665 };
666
667 let parsed = parse_outside_fund_event(&event).unwrap();
668 assert_eq!(parsed.amount, 1000);
669 }
670
671 #[test]
672 fn test_parse_withdraw_event() {
673 let (gx, gy) = generator_rs();
674 let event = EmittedEvent {
675 from_address: make_felt(0x999),
676 keys: vec![*tongo_events::WITHDRAW_EVENT, gx, gy],
677 data: vec![make_felt(5), make_felt(250), make_felt(0x123)],
678 block_hash: None,
679 block_number: Some(300),
680 transaction_hash: make_felt(0xCAFE),
681 event_index: 0,
682 transaction_index: 0,
683 };
684
685 let parsed = parse_withdraw_event(&event).unwrap();
686 assert_eq!(parsed.nonce, 5);
687 assert_eq!(parsed.amount, 250);
688 }
689
690 #[test]
691 fn test_tongo_event_sorting() {
692 let e1 = TongoEvent::Fund(FundEvent {
693 meta: EventMetadata {
694 block_number: Some(100),
695 tx_hash: make_felt(1),
696 },
697 to: krusty_kms_crypto::StarkCurve::generator(),
698 nonce: 0,
699 from: CoreFelt::ZERO,
700 amount: 0,
701 });
702 let e2 = TongoEvent::Fund(FundEvent {
703 meta: EventMetadata {
704 block_number: Some(200),
705 tx_hash: make_felt(2),
706 },
707 to: krusty_kms_crypto::StarkCurve::generator(),
708 nonce: 0,
709 from: CoreFelt::ZERO,
710 amount: 0,
711 });
712
713 let mut events = [e1, e2];
714 events.sort_by_key(|e| std::cmp::Reverse(e.block_number()));
715 assert_eq!(events[0].block_number(), Some(200));
716 assert_eq!(events[1].block_number(), Some(100));
717 }
718
719 #[test]
721 fn test_parsers_return_err_on_short_data() {
722 let (gx, gy) = generator_rs();
723 let base = EmittedEvent {
724 from_address: make_felt(0x999),
725 keys: vec![make_felt(0), gx, gy, gx, gy],
726 data: vec![],
727 block_hash: None,
728 block_number: Some(1),
729 transaction_hash: make_felt(0x1),
730 event_index: 0,
731 transaction_index: 0,
732 };
733
734 assert!(parse_fund_event(&base).is_err());
735 assert!(parse_outside_fund_event(&base).is_err());
736 assert!(parse_withdraw_event(&base).is_err());
737 assert!(parse_ragequit_event(&base).is_err());
738 assert!(parse_rollover_event(&base).is_err());
739 assert!(parse_transfer_event(&base).is_err());
740 assert!(parse_balance_declared_event(&base).is_err());
741 assert!(parse_transfer_declared_event(&base).is_err());
742 }
743}