1use std::sync::Arc;
2
3use alloy_dyn_abi::{DynSolCall, DynSolEvent, DynSolType, DynSolValue, Specifier};
4use alloy_primitives::{I256, U256};
5use anyhow::{anyhow, Context, Result};
6use arrow::{
7 array::{builder, Array, ArrowPrimitiveType, BinaryArray, ListArray, RecordBatch, StructArray},
8 buffer::{NullBuffer, OffsetBuffer},
9 datatypes::{
10 DataType, Field, Fields, Int16Type, Int32Type, Int64Type, Int8Type, Schema, UInt16Type,
11 UInt32Type, UInt64Type, UInt8Type,
12 },
13};
14
15pub fn signature_to_topic0(signature: &str) -> Result<[u8; 32]> {
17 let event = alloy_json_abi::Event::parse(signature).context("parse event signature")?;
18 Ok(event.selector().into())
19}
20
21pub fn decode_call_inputs(
28 signature: &str,
29 data: &BinaryArray,
30 allow_decode_fail: bool,
31) -> Result<RecordBatch> {
32 decode_call_impl::<true>(signature, data, allow_decode_fail)
33}
34
35pub fn decode_call_outputs(
42 signature: &str,
43 data: &BinaryArray,
44 allow_decode_fail: bool,
45) -> Result<RecordBatch> {
46 decode_call_impl::<false>(signature, data, allow_decode_fail)
47}
48
49fn decode_call_impl<const IS_INPUT: bool>(
52 signature: &str,
53 data: &BinaryArray,
54 allow_decode_fail: bool,
55) -> Result<RecordBatch> {
56 let (call, resolved) = resolve_function_signature(signature)?;
57
58 let schema = function_signature_to_arrow_schemas_impl(&call, &resolved)
59 .context("convert event signature to arrow schema")?;
60 let schema = if IS_INPUT { schema.0 } else { schema.1 };
61
62 let mut arrays: Vec<Arc<dyn Array + 'static>> = Vec::with_capacity(schema.fields().len());
63
64 let mut decoded = Vec::<Option<DynSolValue>>::with_capacity(data.len());
65
66 for blob in data.iter() {
67 match blob {
68 Some(blob) => {
69 let decode_res = if IS_INPUT {
70 resolved.abi_decode_input(blob, false)
71 } else {
72 resolved.abi_decode_output(blob, false)
73 };
74 match decode_res {
75 Ok(data) => decoded.push(Some(DynSolValue::Tuple(data))),
76 Err(e) if allow_decode_fail => {
77 log::debug!("failed to decode function call data: {}", e);
78 decoded.push(None);
79 }
80 Err(e) => {
81 return Err(anyhow!("failed to decode function call data: {}", e));
82 }
83 }
84 }
85 None => decoded.push(None),
86 }
87 }
88
89 let sol_type = if IS_INPUT {
90 DynSolType::Tuple(resolved.types().to_vec())
91 } else {
92 DynSolType::Tuple(resolved.returns().types().to_vec())
93 };
94
95 let array = to_arrow(&sol_type, decoded, allow_decode_fail).context("map params to arrow")?;
96 match array.data_type() {
97 DataType::Struct(_) => {
98 let arr = array.as_any().downcast_ref::<StructArray>().unwrap();
99
100 for f in arr.columns().iter() {
101 arrays.push(f.clone());
102 }
103 }
104 _ => unreachable!(),
105 }
106
107 RecordBatch::try_new(Arc::new(schema), arrays).context("construct arrow batch")
108}
109
110pub fn function_signature_to_arrow_schemas(signature: &str) -> Result<(Schema, Schema)> {
112 let (func, resolved) = resolve_function_signature(signature)?;
113 function_signature_to_arrow_schemas_impl(&func, &resolved)
114}
115
116fn function_signature_to_arrow_schemas_impl(
117 func: &alloy_json_abi::Function,
118 call: &DynSolCall,
119) -> Result<(Schema, Schema)> {
120 let mut input_fields = Vec::with_capacity(call.types().len());
121 let mut output_fields = Vec::with_capacity(call.returns().types().len());
122
123 for (i, (sol_t, param)) in call.types().iter().zip(func.inputs.iter()).enumerate() {
124 let dtype = to_arrow_dtype(sol_t).context("map to arrow type")?;
125 let name = if param.name() == "" {
126 format!("param{}", i)
127 } else {
128 param.name().to_owned()
129 };
130 input_fields.push(Arc::new(Field::new(name, dtype, true)));
131 }
132
133 for (i, (sol_t, param)) in call
134 .returns()
135 .types()
136 .iter()
137 .zip(func.outputs.iter())
138 .enumerate()
139 {
140 let dtype = to_arrow_dtype(sol_t).context("map to arrow type")?;
141 let name = if param.name() == "" {
142 format!("param{}", i)
143 } else {
144 param.name().to_owned()
145 };
146 output_fields.push(Arc::new(Field::new(name, dtype, true)));
147 }
148
149 Ok((Schema::new(input_fields), Schema::new(output_fields)))
150}
151
152fn resolve_function_signature(signature: &str) -> Result<(alloy_json_abi::Function, DynSolCall)> {
153 let event = alloy_json_abi::Function::parse(signature).context("parse function signature")?;
154 let resolved = event.resolve().context("resolve function signature")?;
155
156 Ok((event, resolved))
157}
158
159pub fn decode_events(
166 signature: &str,
167 data: &RecordBatch,
168 allow_decode_fail: bool,
169) -> Result<RecordBatch> {
170 let (event, resolved) = resolve_event_signature(signature)?;
171
172 let schema = event_signature_to_arrow_schema_impl(&event, &resolved)
173 .context("convert event signature to arrow schema")?;
174
175 let mut arrays: Vec<Arc<dyn Array + 'static>> = Vec::with_capacity(schema.fields().len());
176
177 for (sol_type, topic_name) in resolved
178 .indexed()
179 .iter()
180 .zip(["topic1", "topic2", "topic3"].iter())
181 {
182 let col = data
183 .column_by_name(topic_name)
184 .context("get topic column")?
185 .as_any()
186 .downcast_ref::<BinaryArray>()
187 .context("get topic column as binary")?;
188
189 let mut decoded = Vec::<Option<DynSolValue>>::with_capacity(col.len());
190
191 for blob in col.iter() {
192 match blob {
193 Some(blob) => match sol_type.abi_decode(blob) {
194 Ok(data) => decoded.push(Some(data)),
195 Err(e) if allow_decode_fail => {
196 log::debug!("failed to decode a topic: {}", e);
197 decoded.push(None);
198 }
199 Err(e) => {
200 return Err(anyhow!("failed to decode a topic: {}", e));
201 }
202 },
203 None => decoded.push(None),
204 }
205 }
206
207 arrays.push(to_arrow(sol_type, decoded, allow_decode_fail).context("map topic to arrow")?);
208 }
209
210 let body_col = data
211 .column_by_name("data")
212 .context("get data column")?
213 .as_any()
214 .downcast_ref::<BinaryArray>()
215 .context("get data column as binary")?;
216 let body_sol_type = DynSolType::Tuple(resolved.body().to_vec());
217
218 let mut body_decoded = Vec::<Option<DynSolValue>>::with_capacity(body_col.len());
219
220 for blob in body_col.iter() {
221 match blob {
222 Some(blob) => match body_sol_type.abi_decode_sequence(blob) {
223 Ok(data) => body_decoded.push(Some(data)),
224 Err(e) if allow_decode_fail => {
225 log::debug!("failed to decode body: {}", e);
226 body_decoded.push(None);
227 }
228 Err(e) => {
229 return Err(anyhow!("failed to decode body: {}", e));
230 }
231 },
232 None => body_decoded.push(None),
233 }
234 }
235
236 let body_array =
237 to_arrow(&body_sol_type, body_decoded, allow_decode_fail).context("map body to arrow")?;
238 match body_array.data_type() {
239 DataType::Struct(_) => {
240 let arr = body_array.as_any().downcast_ref::<StructArray>().unwrap();
241
242 for f in arr.columns().iter() {
243 arrays.push(f.clone());
244 }
245 }
246 _ => unreachable!(),
247 }
248
249 RecordBatch::try_new(Arc::new(schema), arrays).context("construct arrow batch")
250}
251
252pub fn event_signature_to_arrow_schema(signature: &str) -> Result<Schema> {
254 let (resolved, event) = resolve_event_signature(signature)?;
255 event_signature_to_arrow_schema_impl(&resolved, &event)
256}
257
258fn event_signature_to_arrow_schema_impl(
259 sig: &alloy_json_abi::Event,
260 event: &DynSolEvent,
261) -> Result<Schema> {
262 let num_fields = event.indexed().len() + event.body().len();
263 let mut fields = Vec::<Arc<Field>>::with_capacity(num_fields);
264 let mut names = Vec::with_capacity(num_fields);
265
266 for (i, input) in sig.inputs.iter().enumerate() {
267 if input.indexed {
268 let name = if input.name.is_empty() {
269 format!("param{}", i)
270 } else {
271 input.name.clone()
272 };
273 names.push(name);
274 }
275 }
276 for (i, input) in sig.inputs.iter().enumerate() {
277 if !input.indexed {
278 let name = if input.name.is_empty() {
279 format!("param{}", i)
280 } else {
281 input.name.clone()
282 };
283 names.push(name);
284 }
285 }
286
287 for (sol_t, name) in event.indexed().iter().chain(event.body()).zip(names) {
288 let dtype = to_arrow_dtype(sol_t).context("map to arrow type")?;
289 fields.push(Arc::new(Field::new(name, dtype, true)));
290 }
291
292 Ok(Schema::new(fields))
293}
294
295fn resolve_event_signature(signature: &str) -> Result<(alloy_json_abi::Event, DynSolEvent)> {
296 let event = alloy_json_abi::Event::parse(signature).context("parse event signature")?;
297 let resolved = event.resolve().context("resolve event signature")?;
298
299 Ok((event, resolved))
300}
301
302fn to_arrow_dtype(sol_type: &DynSolType) -> Result<DataType> {
303 match sol_type {
304 DynSolType::Bool => Ok(DataType::Boolean),
305 DynSolType::Bytes => Ok(DataType::Binary),
306 DynSolType::String => Ok(DataType::Utf8),
307 DynSolType::Address => Ok(DataType::Binary),
308 DynSolType::Int(num_bits) => Ok(num_bits_to_int_type(*num_bits)),
309 DynSolType::Uint(num_bits) => Ok(num_bits_to_uint_type(*num_bits)),
310 DynSolType::Array(inner_type) => {
311 let inner_type = to_arrow_dtype(inner_type).context("map inner")?;
312 Ok(DataType::List(Arc::new(Field::new("", inner_type, true))))
313 }
314 DynSolType::Function => Err(anyhow!(
315 "decoding 'Function' typed value in function signature isn't supported."
316 )),
317 DynSolType::FixedArray(inner_type, _) => {
318 let inner_type = to_arrow_dtype(inner_type).context("map inner")?;
319 Ok(DataType::List(Arc::new(Field::new("", inner_type, true))))
320 }
321 DynSolType::Tuple(fields) => {
322 let mut arrow_fields = Vec::<Arc<Field>>::with_capacity(fields.len());
323
324 for (i, f) in fields.iter().enumerate() {
325 let inner_dt = to_arrow_dtype(f).context("map field dt")?;
326 arrow_fields.push(Arc::new(Field::new(format!("param{}", i), inner_dt, true)));
327 }
328
329 Ok(DataType::Struct(Fields::from(arrow_fields)))
330 }
331 DynSolType::FixedBytes(_) => Ok(DataType::Binary),
332 }
333}
334
335fn num_bits_to_uint_type(num_bits: usize) -> DataType {
336 if num_bits <= 8 {
337 DataType::UInt8
338 } else if num_bits <= 16 {
339 DataType::UInt16
340 } else if num_bits <= 32 {
341 DataType::UInt32
342 } else if num_bits <= 64 {
343 DataType::UInt64
344 } else if num_bits <= 128 {
345 DataType::Decimal128(38, 0)
346 } else if num_bits <= 256 {
347 DataType::Decimal256(76, 0)
348 } else {
349 unreachable!()
350 }
351}
352
353fn num_bits_to_int_type(num_bits: usize) -> DataType {
354 if num_bits <= 8 {
355 DataType::Int8
356 } else if num_bits <= 16 {
357 DataType::Int16
358 } else if num_bits <= 32 {
359 DataType::Int32
360 } else if num_bits <= 64 {
361 DataType::Int64
362 } else if num_bits <= 128 {
363 DataType::Decimal128(38, 0)
364 } else if num_bits <= 256 {
365 DataType::Decimal256(76, 0)
366 } else {
367 unreachable!()
368 }
369}
370
371fn to_arrow(
372 sol_type: &DynSolType,
373 sol_values: Vec<Option<DynSolValue>>,
374 allow_decode_fail: bool,
375) -> Result<Arc<dyn Array>> {
376 match sol_type {
377 DynSolType::Bool => to_bool(&sol_values),
378 DynSolType::Bytes => to_binary(&sol_values),
379 DynSolType::String => to_string(&sol_values),
380 DynSolType::Address => to_binary(&sol_values),
381 DynSolType::Int(num_bits) => to_int(*num_bits, &sol_values, allow_decode_fail),
382 DynSolType::Uint(num_bits) => to_uint(*num_bits, &sol_values, allow_decode_fail),
383 DynSolType::Array(inner_type) => to_list(inner_type, sol_values, allow_decode_fail),
384 DynSolType::Function => Err(anyhow!(
385 "decoding 'Function' typed value in function signature isn't supported."
386 )),
387 DynSolType::FixedArray(inner_type, _) => to_list(inner_type, sol_values, allow_decode_fail),
388 DynSolType::Tuple(fields) => to_struct(fields, sol_values, allow_decode_fail),
389 DynSolType::FixedBytes(_) => to_binary(&sol_values),
390 }
391}
392
393fn to_int(
394 num_bits: usize,
395 sol_values: &[Option<DynSolValue>],
396 allow_decode_fail: bool,
397) -> Result<Arc<dyn Array>> {
398 match num_bits_to_int_type(num_bits) {
399 DataType::Int8 => to_int_impl::<Int8Type>(num_bits, sol_values),
400 DataType::Int16 => to_int_impl::<Int16Type>(num_bits, sol_values),
401 DataType::Int32 => to_int_impl::<Int32Type>(num_bits, sol_values),
402 DataType::Int64 => to_int_impl::<Int64Type>(num_bits, sol_values),
403 DataType::Decimal128(_, _) => to_decimal128(num_bits, sol_values),
404 DataType::Decimal256(_, _) => to_decimal256(num_bits, sol_values, allow_decode_fail),
405 _ => unreachable!(),
406 }
407}
408
409fn to_uint(
410 num_bits: usize,
411 sol_values: &[Option<DynSolValue>],
412 allow_decode_fail: bool,
413) -> Result<Arc<dyn Array>> {
414 match num_bits_to_int_type(num_bits) {
415 DataType::UInt8 => to_int_impl::<UInt8Type>(num_bits, sol_values),
416 DataType::UInt16 => to_int_impl::<UInt16Type>(num_bits, sol_values),
417 DataType::UInt32 => to_int_impl::<UInt32Type>(num_bits, sol_values),
418 DataType::UInt64 => to_int_impl::<UInt64Type>(num_bits, sol_values),
419 DataType::Decimal128(_, _) => to_decimal128(num_bits, sol_values),
420 DataType::Decimal256(_, _) => to_decimal256(num_bits, sol_values, allow_decode_fail),
421 _ => unreachable!(),
422 }
423}
424
425fn to_decimal128(num_bits: usize, sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
426 let mut builder = builder::Decimal128Builder::new();
427
428 for val in sol_values.iter() {
429 match val {
430 Some(val) => match val {
431 DynSolValue::Int(v, nb) => {
432 assert_eq!(num_bits, *nb);
433
434 let v = i128::try_from(*v).context("convert to i128")?;
435
436 builder.append_value(v);
437 }
438 DynSolValue::Uint(v, nb) => {
439 assert_eq!(num_bits, *nb);
440
441 let v = i128::try_from(*v).context("convert to i128")?;
442
443 builder.append_value(v);
444 }
445 _ => {
446 return Err(anyhow!(
447 "found unexpected value. Expected: bool, Found: {:?}",
448 val
449 ));
450 }
451 },
452 None => {
453 builder.append_null();
454 }
455 }
456 }
457
458 builder = builder.with_data_type(DataType::Decimal128(38, 0));
459
460 Ok(Arc::new(builder.finish()))
461}
462
463fn to_decimal256(
464 num_bits: usize,
465 sol_values: &[Option<DynSolValue>],
466 allow_decode_fail: bool,
467) -> Result<Arc<dyn Array>> {
468 let mut builder = builder::Decimal256Builder::new();
469
470 for val in sol_values.iter() {
471 match val {
472 Some(val) => match val {
473 DynSolValue::Int(v, nb) => {
474 assert_eq!(num_bits, *nb);
475
476 let v = arrow::datatypes::i256::from_be_bytes(v.to_be_bytes::<32>());
477
478 builder.append_value(v);
479 }
480 DynSolValue::Uint(v, nb) => {
481 assert_eq!(num_bits, *nb);
482 match I256::try_from(*v).context("try u256 to i256") {
483 Ok(v) => builder.append_value(arrow::datatypes::i256::from_be_bytes(
484 v.to_be_bytes::<32>(),
485 )),
486 Err(e) => {
487 if allow_decode_fail {
488 log::debug!("failed to decode u256: {}", e);
489 builder.append_null();
490 } else {
491 return Err(e);
492 }
493 }
494 }
495 }
496 _ => {
497 return Err(anyhow!(
498 "found unexpected value. Expected: bool, Found: {:?}",
499 val
500 ));
501 }
502 },
503 None => {
504 builder.append_null();
505 }
506 }
507 }
508
509 builder = builder.with_data_type(DataType::Decimal256(76, 0));
510
511 Ok(Arc::new(builder.finish()))
512}
513
514fn to_int_impl<T>(num_bits: usize, sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>>
515where
516 T: ArrowPrimitiveType,
517 T::Native: TryFrom<I256> + TryFrom<U256>,
518{
519 let mut builder = builder::PrimitiveBuilder::<T>::new();
520
521 for val in sol_values.iter() {
522 match val {
523 Some(val) => match val {
524 DynSolValue::Int(v, nb) => {
525 assert_eq!(num_bits, *nb);
526 builder.append_value(match T::Native::try_from(*v) {
527 Ok(v) => v,
528 Err(_) => unreachable!(),
529 });
530 }
531 DynSolValue::Uint(v, nb) => {
532 assert_eq!(num_bits, *nb);
533 builder.append_value(match T::Native::try_from(*v) {
534 Ok(v) => v,
535 Err(_) => unreachable!(),
536 });
537 }
538 _ => {
539 return Err(anyhow!(
540 "found unexpected value. Expected: bool, Found: {:?}",
541 val
542 ));
543 }
544 },
545 None => {
546 builder.append_null();
547 }
548 }
549 }
550
551 Ok(Arc::new(builder.finish()))
552}
553
554fn to_list(
555 sol_type: &DynSolType,
556 sol_values: Vec<Option<DynSolValue>>,
557 allow_decode_fail: bool,
558) -> Result<Arc<dyn Array>> {
559 let mut lengths = Vec::with_capacity(sol_values.len());
560 let mut values = Vec::with_capacity(sol_values.len() * 2);
561 let mut validity = Vec::with_capacity(sol_values.len() * 2);
562
563 let mut all_valid = true;
564
565 for val in sol_values {
566 match val {
567 Some(val) => match val {
568 DynSolValue::Array(inner_vals) | DynSolValue::FixedArray(inner_vals) => {
569 lengths.push(inner_vals.len());
570 values.extend(inner_vals.into_iter().map(Some));
571 validity.push(true);
572 }
573 _ => {
574 return Err(anyhow!(
575 "found unexpected value. Expected list type, Found: {:?}",
576 val
577 ));
578 }
579 },
580 None => {
581 lengths.push(0);
582 validity.push(false);
583 all_valid = false;
584 }
585 }
586 }
587
588 let values = to_arrow(sol_type, values, allow_decode_fail).context("map inner")?;
589 let field = Field::new(
590 "",
591 to_arrow_dtype(sol_type).context("construct data type")?,
592 true,
593 );
594 let list_arr = ListArray::try_new(
595 Arc::new(field),
596 OffsetBuffer::from_lengths(lengths),
597 values,
598 if all_valid {
599 None
600 } else {
601 Some(NullBuffer::from(validity))
602 },
603 )
604 .context("construct list array")?;
605 Ok(Arc::new(list_arr))
606}
607
608fn to_struct(
609 fields: &[DynSolType],
610 sol_values: Vec<Option<DynSolValue>>,
611 allow_decode_fail: bool,
612) -> Result<Arc<dyn Array>> {
613 let mut values = vec![Vec::with_capacity(sol_values.len()); fields.len()];
614
615 for val in sol_values.iter() {
619 match val {
620 Some(val) => match val {
621 DynSolValue::Tuple(inner_vals) => {
622 if values.len() != inner_vals.len() {
623 return Err(anyhow!(
624 "found unexpected length tuple value. Expected: {}, Found: {}",
625 values.len(),
626 inner_vals.len()
627 ));
628 }
629 for (v, inner) in values.iter_mut().zip(inner_vals) {
630 v.push(Some(inner.clone()));
631 }
632 }
633 _ => {
634 return Err(anyhow!(
635 "found unexpected value. Expected: tuple, Found: {:?}",
636 val
637 ));
638 }
639 },
640 None => {
641 for v in values.iter_mut() {
642 v.push(None);
643 }
644 }
645 }
646 }
647
648 let mut arrays = Vec::with_capacity(fields.len());
649
650 for (sol_type, arr_vals) in fields.iter().zip(values.into_iter()) {
651 arrays.push(to_arrow(sol_type, arr_vals, allow_decode_fail)?);
652 }
653
654 let fields = arrays
655 .iter()
656 .enumerate()
657 .map(|(i, arr)| Field::new(format!("param{}", i), arr.data_type().clone(), true))
658 .collect::<Vec<_>>();
659 let schema = Arc::new(Schema::new(fields));
660
661 let batch = RecordBatch::try_new(schema, arrays).context("construct record batch")?;
662
663 Ok(Arc::new(StructArray::from(batch)))
664}
665
666fn to_bool(sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
667 let mut builder = builder::BooleanBuilder::new();
668
669 for val in sol_values.iter() {
670 match val {
671 Some(val) => match val {
672 DynSolValue::Bool(b) => {
673 builder.append_value(*b);
674 }
675 _ => {
676 return Err(anyhow!(
677 "found unexpected value. Expected: bool, Found: {:?}",
678 val
679 ));
680 }
681 },
682 None => {
683 builder.append_null();
684 }
685 }
686 }
687
688 Ok(Arc::new(builder.finish()))
689}
690
691fn to_binary(sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
692 let mut builder = builder::BinaryBuilder::new();
693
694 for val in sol_values.iter() {
695 match val {
696 Some(val) => match val {
697 DynSolValue::Bytes(data) => {
698 builder.append_value(data);
699 }
700 DynSolValue::FixedBytes(data, _) => {
701 builder.append_value(data);
702 }
703 DynSolValue::Address(data) => {
704 builder.append_value(data);
705 }
706 DynSolValue::Uint(v, _) => {
707 builder.append_value(v.to_be_bytes::<32>());
708 }
709 DynSolValue::Int(v, _) => {
710 builder.append_value(v.to_be_bytes::<32>());
711 }
712 _ => {
713 return Err(anyhow!(
714 "found unexpected value. Expected a binary type, Found: {:?}",
715 val
716 ));
717 }
718 },
719 None => {
720 builder.append_null();
721 }
722 }
723 }
724
725 Ok(Arc::new(builder.finish()))
726}
727
728fn to_string(sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
729 let mut builder = builder::StringBuilder::new();
730
731 for val in sol_values.iter() {
732 match val {
733 Some(val) => match val {
734 DynSolValue::String(s) => {
735 builder.append_value(s);
736 }
737 _ => {
738 return Err(anyhow!(
739 "found unexpected value. Expected string, Found: {:?}",
740 val
741 ));
742 }
743 },
744 None => {
745 builder.append_null();
746 }
747 }
748 }
749
750 Ok(Arc::new(builder.finish()))
751}
752
753#[cfg(test)]
754mod tests {
755 use super::*;
756
757 #[test]
758 fn nested_event_signature_to_schema() {
759 let sig = "ConfiguredQuests(address editor, uint256[][], address indexed my_addr, (bool,bool[],(bool, uint256[]))[] questDetails)";
760
761 let schema = event_signature_to_arrow_schema(sig).unwrap();
762
763 let expected_schema = Schema::new(vec![
764 Arc::new(Field::new("my_addr", DataType::Binary, true)),
765 Arc::new(Field::new("editor", DataType::Binary, true)),
766 Arc::new(Field::new(
767 "param1",
768 DataType::List(Arc::new(Field::new(
769 "",
770 DataType::List(Arc::new(Field::new("", DataType::Decimal256(76, 0), true))),
771 true,
772 ))),
773 true,
774 )),
775 Arc::new(Field::new(
776 "questDetails",
777 DataType::List(Arc::new(Field::new(
778 "",
779 DataType::Struct(Fields::from(vec![
780 Arc::new(Field::new("param0", DataType::Boolean, true)),
781 Arc::new(Field::new(
782 "param1",
783 DataType::List(Arc::new(Field::new("", DataType::Boolean, true))),
784 true,
785 )),
786 Arc::new(Field::new(
787 "param2",
788 DataType::Struct(Fields::from(vec![
789 Arc::new(Field::new("param0", DataType::Boolean, true)),
790 Arc::new(Field::new(
791 "param1",
792 DataType::List(Arc::new(Field::new(
793 "",
794 DataType::Decimal256(76, 0),
795 true,
796 ))),
797 true,
798 )),
799 ])),
800 true,
801 )),
802 ])),
803 true,
804 ))),
805 true,
806 )),
807 ]);
808
809 assert_eq!(schema, expected_schema);
810 }
811
812 #[test]
813 fn i256_to_arrow_i256() {
814 for val in [
815 I256::MIN,
816 I256::MAX,
817 I256::MAX / I256::try_from(2i32).unwrap(),
818 ] {
819 let out = arrow::datatypes::i256::from_be_bytes(val.to_be_bytes::<32>());
820
821 assert_eq!(val.to_string(), out.to_string());
822 }
823 }
824}