1use super::{runtime::*, *};
2
3#[derive(Clone, Debug)]
4pub(super) struct SymbolicCalldata {
5 pub(super) size: usize,
6 pub(super) bytes: Vec<SymWord>,
7 pub(super) inputs: Vec<SymbolicInput>,
8 pub(super) constraints: Vec<BoolExpr>,
9}
10
11impl SymbolicCalldata {
12 #[cfg(test)]
14 pub(super) fn new(function: &Function, config: &SymbolicConfig) -> Result<Self, SymbolicError> {
15 Ok(Self::variants(function, config)?.remove(0))
16 }
17
18 pub(super) fn variants(
20 function: &Function,
21 config: &SymbolicConfig,
22 ) -> Result<Vec<Self>, SymbolicError> {
23 Self::variants_with_prefix(function, config, "calldata")
24 }
25
26 pub(super) fn selector_only(function: &Function) -> Result<Self, SymbolicError> {
28 if !function.inputs.is_empty() {
29 return Err(SymbolicError::UnsupportedAbi(format!(
30 "symbolic invariant `{}` must take no parameters",
31 function.name
32 )));
33 }
34 let bytes = function
35 .selector()
36 .iter()
37 .copied()
38 .map(|byte| SymWord::Concrete(U256::from(byte)))
39 .collect::<Vec<_>>();
40 Ok(Self { size: bytes.len(), bytes, inputs: Vec::new(), constraints: Vec::new() })
41 }
42
43 pub(super) fn variants_with_prefix(
45 function: &Function,
46 config: &SymbolicConfig,
47 prefix: impl AsRef<str>,
48 ) -> Result<Vec<Self>, SymbolicError> {
49 let prefix = prefix.as_ref();
50 let variant_limit = calldata_variant_limit(config);
51 let mut variants = vec![(SymbolicAbiBuilder::new(config), Vec::new())];
52 for (idx, input) in function.inputs.iter().enumerate() {
53 let ty = input.selector_type();
54 let mut next_variants = Vec::new();
55 for (builder, inputs) in variants {
56 for (builder, input) in SymbolicInput::variants(
57 builder,
58 prefix,
59 idx,
60 Some(input.name.as_str()),
61 ty.as_ref(),
62 )? {
63 let mut inputs = inputs.clone();
64 inputs.push(input);
65 push_variant(&mut next_variants, (builder, inputs), variant_limit)?;
66 }
67 }
68 variants = next_variants;
69 }
70
71 validate_positional_dynamic_lengths(
72 config,
73 variants.iter().map(|(builder, _)| builder.positional_dynamic_index).max().unwrap_or(0),
74 )?;
75
76 variants
77 .into_iter()
78 .map(|(builder, inputs)| {
79 let mut bytes = function
80 .selector()
81 .iter()
82 .copied()
83 .map(|byte| SymWord::Concrete(U256::from(byte)))
84 .collect::<Vec<_>>();
85 bytes.extend(encode_sequence(inputs.iter().map(|input| &input.value)));
86 if bytes.len() > config.max_calldata_bytes as usize {
87 return Err(SymbolicError::Unsupported(
88 "symbolic calldata size exceeds configured max",
89 ));
90 }
91
92 Ok(Self { size: bytes.len(), bytes, inputs, constraints: builder.constraints })
93 })
94 .collect()
95 }
96
97 #[cfg(test)]
98 pub(super) fn load(&self, offset: usize) -> Result<SymWord, SymbolicError> {
100 Ok(word_from_bytes((0..32).map(|idx| self.byte(offset + idx))))
101 }
102
103 #[cfg(test)]
104 pub(super) fn byte(&self, offset: usize) -> SymWord {
106 self.bytes.get(offset).cloned().unwrap_or_else(SymWord::zero)
107 }
108
109 pub(super) fn call_data(&self) -> SymCalldata {
111 SymCalldata {
112 size: self.size,
113 size_word: SymWord::Concrete(U256::from(self.size)),
114 bytes: self.bytes.clone(),
115 }
116 }
117
118 pub(super) fn model_to_args(
120 &self,
121 model: &BTreeMap<String, U256>,
122 ) -> Result<Vec<DynSolValue>, SymbolicError> {
123 self.inputs.iter().map(|input| input.value.model_value(model)).collect()
124 }
125}
126
127#[derive(Clone, Debug)]
128pub(super) struct SymbolicInput {
129 pub(super) value: SymbolicAbiValue,
130}
131
132impl SymbolicInput {
133 pub(super) fn variants<'a>(
135 builder: SymbolicAbiBuilder<'a>,
136 prefix: &str,
137 idx: usize,
138 abi_name: Option<&str>,
139 ty: &str,
140 ) -> Result<Vec<(SymbolicAbiBuilder<'a>, Self)>, SymbolicError> {
141 let ty =
142 DynSolType::parse(ty).map_err(|_| SymbolicError::UnsupportedAbi(ty.to_string()))?;
143 let name = format!("{prefix}_{idx}");
144 let aliases =
145 abi_name.filter(|name| !name.is_empty()).map(str::to_string).into_iter().collect();
146 builder.value_variants(name, aliases, &ty).map(|variants| {
147 variants.into_iter().map(|(builder, value)| (builder, Self { value })).collect()
148 })
149 }
150}
151
152#[derive(Clone)]
153pub(super) struct SymbolicAbiBuilder<'a> {
154 pub(super) config: &'a SymbolicConfig,
155 pub(super) constraints: Vec<BoolExpr>,
156 pub(super) positional_dynamic_index: usize,
157}
158
159impl<'a> SymbolicAbiBuilder<'a> {
160 pub(super) const fn new(config: &'a SymbolicConfig) -> Self {
162 Self { config, constraints: Vec::new(), positional_dynamic_index: 0 }
163 }
164
165 pub(super) fn value(
167 &mut self,
168 name: String,
169 aliases: Vec<String>,
170 ty: &DynSolType,
171 ) -> Result<SymbolicAbiValue, SymbolicError> {
172 Ok(match ty {
173 DynSolType::Bool => {
174 let word = self.fresh_word(name);
175 self.constraints.push(BoolExpr::cmp(
176 BoolExprOp::Ult,
177 word.clone().into_expr(),
178 Expr::Const(U256::from(2)),
179 ));
180 SymbolicAbiValue::Bool { word }
181 }
182 DynSolType::Uint(bits) => {
183 let word = self.fresh_word(name);
184 self.constrain_uint(&word, *bits);
185 SymbolicAbiValue::Uint { bits: *bits, word }
186 }
187 DynSolType::Int(bits) => {
188 let word = self.fresh_word(name);
189 self.constrain_int(&word, *bits);
190 SymbolicAbiValue::Int { bits: *bits, word }
191 }
192 DynSolType::FixedBytes(size) => SymbolicAbiValue::FixedBytes {
193 bytes: (0..*size)
194 .map(|idx| self.fresh_byte(format!("{name}_{idx}"), false))
195 .collect(),
196 size: *size,
197 },
198 DynSolType::Address => {
199 let word = self.fresh_word(name);
200 self.constrain_uint(&word, 160);
201 SymbolicAbiValue::Address { word }
202 }
203 DynSolType::Function => {
204 return Err(SymbolicError::UnsupportedAbi("function".to_string()));
205 }
206 DynSolType::Bytes => {
207 let len = self.next_dynamic_length(&name, &aliases, DynamicKind::Bytes)?;
208 SymbolicAbiValue::Bytes {
209 len: SymWord::Concrete(U256::from(len)),
210 bytes: (0..len)
211 .map(|idx| self.fresh_byte(format!("{name}_{idx}"), false))
212 .collect(),
213 }
214 }
215 DynSolType::String => {
216 let len = self.next_dynamic_length(&name, &aliases, DynamicKind::String)?;
217 SymbolicAbiValue::String {
218 bytes: (0..len)
219 .map(|idx| self.fresh_byte(format!("{name}_{idx}"), true))
220 .collect(),
221 }
222 }
223 DynSolType::Array(inner) => {
224 let len = self.next_dynamic_length(&name, &aliases, DynamicKind::Array)?;
225 SymbolicAbiValue::Array {
226 elements: (0..len)
227 .map(|idx| {
228 self.value(format!("{name}_{idx}"), child_aliases(&aliases, idx), inner)
229 })
230 .collect::<Result<Vec<_>, _>>()?,
231 }
232 }
233 DynSolType::FixedArray(inner, len) => SymbolicAbiValue::FixedArray {
234 elements: (0..*len)
235 .map(|idx| {
236 self.value(format!("{name}_{idx}"), child_aliases(&aliases, idx), inner)
237 })
238 .collect::<Result<Vec<_>, _>>()?,
239 },
240 DynSolType::Tuple(types) => SymbolicAbiValue::Tuple {
241 elements: types
242 .iter()
243 .enumerate()
244 .map(|(idx, ty)| {
245 self.value(format!("{name}_{idx}"), child_aliases(&aliases, idx), ty)
246 })
247 .collect::<Result<Vec<_>, _>>()?,
248 },
249 DynSolType::CustomStruct { tuple, .. } => SymbolicAbiValue::Tuple {
250 elements: tuple
251 .iter()
252 .enumerate()
253 .map(|(idx, ty)| {
254 self.value(format!("{name}_{idx}"), child_aliases(&aliases, idx), ty)
255 })
256 .collect::<Result<Vec<_>, _>>()?,
257 },
258 })
259 }
260
261 pub(super) fn value_variants(
263 self,
264 name: String,
265 aliases: Vec<String>,
266 ty: &DynSolType,
267 ) -> Result<Vec<(Self, SymbolicAbiValue)>, SymbolicError> {
268 Ok(match ty {
269 DynSolType::Bytes => {
270 let mut builder = self;
271 let lengths =
272 builder.next_dynamic_length_options(&name, &aliases, DynamicKind::Bytes)?;
273 let limit = calldata_variant_limit(builder.config);
274 let mut variants = Vec::new();
275 for len in lengths {
276 let mut builder = builder.clone();
277 let value = SymbolicAbiValue::Bytes {
278 len: SymWord::Concrete(U256::from(len)),
279 bytes: (0..len as usize)
280 .map(|idx| builder.fresh_byte(format!("{name}_{idx}"), false))
281 .collect(),
282 };
283 push_variant(&mut variants, (builder, value), limit)?;
284 }
285 variants
286 }
287 DynSolType::String => {
288 let mut builder = self;
289 let lengths =
290 builder.next_dynamic_length_options(&name, &aliases, DynamicKind::String)?;
291 let limit = calldata_variant_limit(builder.config);
292 let mut variants = Vec::new();
293 for len in lengths {
294 let mut builder = builder.clone();
295 let value = SymbolicAbiValue::String {
296 bytes: (0..len as usize)
297 .map(|idx| builder.fresh_byte(format!("{name}_{idx}"), true))
298 .collect(),
299 };
300 push_variant(&mut variants, (builder, value), limit)?;
301 }
302 variants
303 }
304 DynSolType::Array(inner) => {
305 let mut builder = self;
306 let lengths =
307 builder.next_dynamic_length_options(&name, &aliases, DynamicKind::Array)?;
308 let limit = calldata_variant_limit(builder.config);
309 let mut variants = Vec::new();
310 for len in lengths {
311 for (builder, elements) in builder.clone().array_elements_variants(
312 &name,
313 &aliases,
314 inner,
315 len as usize,
316 )? {
317 push_variant(
318 &mut variants,
319 (builder, SymbolicAbiValue::Array { elements }),
320 limit,
321 )?;
322 }
323 }
324 variants
325 }
326 DynSolType::FixedArray(inner, len) => {
327 self.array_elements_variants(&name, &aliases, inner, *len).map(|variants| {
328 variants
329 .into_iter()
330 .map(|(builder, elements)| {
331 (builder, SymbolicAbiValue::FixedArray { elements })
332 })
333 .collect()
334 })?
335 }
336 DynSolType::Tuple(types) => self
337 .tuple_elements_variants(&name, &aliases, types)?
338 .into_iter()
339 .map(|(builder, elements)| (builder, SymbolicAbiValue::Tuple { elements }))
340 .collect(),
341 DynSolType::CustomStruct { tuple, .. } => self
342 .tuple_elements_variants(&name, &aliases, tuple)?
343 .into_iter()
344 .map(|(builder, elements)| (builder, SymbolicAbiValue::Tuple { elements }))
345 .collect(),
346 _ => {
347 let mut builder = self;
348 let value = builder.value(name, aliases, ty)?;
349 vec![(builder, value)]
350 }
351 })
352 }
353
354 pub(super) fn array_elements_variants(
356 self,
357 name: &str,
358 aliases: &[String],
359 inner: &DynSolType,
360 len: usize,
361 ) -> Result<Vec<(Self, Vec<SymbolicAbiValue>)>, SymbolicError> {
362 let limit = calldata_variant_limit(self.config);
363 let mut variants = vec![(self, Vec::with_capacity(len))];
364 for idx in 0..len {
365 let mut next_variants = Vec::new();
366 for (builder, elements) in variants {
367 for (builder, value) in builder.value_variants(
368 format!("{name}_{idx}"),
369 child_aliases(aliases, idx),
370 inner,
371 )? {
372 let mut elements = elements.clone();
373 elements.push(value);
374 push_variant(&mut next_variants, (builder, elements), limit)?;
375 }
376 }
377 variants = next_variants;
378 }
379 Ok(variants)
380 }
381
382 pub(super) fn tuple_elements_variants(
384 self,
385 name: &str,
386 aliases: &[String],
387 types: &[DynSolType],
388 ) -> Result<Vec<(Self, Vec<SymbolicAbiValue>)>, SymbolicError> {
389 let limit = calldata_variant_limit(self.config);
390 let mut variants = vec![(self, Vec::with_capacity(types.len()))];
391 for (idx, ty) in types.iter().enumerate() {
392 let mut next_variants = Vec::new();
393 for (builder, elements) in variants {
394 for (builder, value) in builder.value_variants(
395 format!("{name}_{idx}"),
396 child_aliases(aliases, idx),
397 ty,
398 )? {
399 let mut elements = elements.clone();
400 elements.push(value);
401 push_variant(&mut next_variants, (builder, elements), limit)?;
402 }
403 }
404 variants = next_variants;
405 }
406 Ok(variants)
407 }
408
409 pub(super) const fn fresh_word(&self, name: String) -> SymWord {
411 SymWord::Expr(Expr::Var(name))
412 }
413
414 pub(super) fn fresh_byte(&mut self, name: String, printable: bool) -> SymWord {
416 let word = self.fresh_word(name);
417 self.constraints.push(BoolExpr::cmp(
418 BoolExprOp::Ult,
419 word.clone().into_expr(),
420 Expr::Const(U256::from(256)),
421 ));
422 if printable {
423 self.constraints.push(BoolExpr::cmp(
424 BoolExprOp::Uge,
425 word.clone().into_expr(),
426 Expr::Const(U256::from(0x20)),
427 ));
428 self.constraints.push(BoolExpr::cmp(
429 BoolExprOp::Ule,
430 word.clone().into_expr(),
431 Expr::Const(U256::from(0x7e)),
432 ));
433 }
434 word
435 }
436
437 pub(super) fn next_dynamic_length(
439 &mut self,
440 name: &str,
441 aliases: &[String],
442 kind: DynamicKind,
443 ) -> Result<usize, SymbolicError> {
444 Ok(first_dynamic_length(
445 &self.next_dynamic_length_options(name, aliases, kind)?,
446 "symbolic dynamic length",
447 )? as usize)
448 }
449
450 pub(super) fn next_dynamic_length_options(
452 &mut self,
453 name: &str,
454 aliases: &[String],
455 kind: DynamicKind,
456 ) -> Result<Vec<u32>, SymbolicError> {
457 let named_lengths = std::iter::once(name)
458 .chain(aliases.iter().map(String::as_str))
459 .find_map(|name| self.config.dynamic_lengths.get(name));
460
461 let lengths = if let Some(lengths) = named_lengths {
462 lengths.clone()
463 } else if let Some(lengths) = kind.default_lengths(self.config) {
464 lengths.to_vec()
465 } else if let Some(len) =
466 self.config.array_lengths.get(self.positional_dynamic_index).copied()
467 {
468 self.positional_dynamic_index += 1;
469 vec![len]
470 } else {
471 vec![self.config.default_dynamic_length]
472 };
473
474 if lengths.is_empty() {
475 return Err(SymbolicError::UnsupportedAbi(
476 "symbolic dynamic length set must not be empty".to_string(),
477 ));
478 }
479 for len in &lengths {
480 if *len > self.config.max_dynamic_length {
481 return Err(SymbolicError::UnsupportedAbi(format!(
482 "symbolic {} length {len} exceeds max_dynamic_length {}",
483 kind.name(),
484 self.config.max_dynamic_length
485 )));
486 }
487 }
488 Ok(lengths)
489 }
490
491 pub(super) fn constrain_uint(&mut self, word: &SymWord, bits: usize) {
493 if bits < 256 {
494 self.constraints.push(BoolExpr::cmp(
495 BoolExprOp::Ult,
496 word.clone().into_expr(),
497 Expr::Const(U256::from(1) << bits),
498 ));
499 }
500 }
501
502 pub(super) fn constrain_int(&mut self, word: &SymWord, bits: usize) {
504 if bits < 256 {
505 let byte_index = U256::from(bits / 8 - 1);
506 self.constraints.push(BoolExpr::eq(
507 word.clone().into_expr(),
508 signextend_word(byte_index, word.clone()).into_expr(),
509 ));
510 }
511 }
512}
513
514fn validate_positional_dynamic_lengths(
516 config: &SymbolicConfig,
517 max_positional_dynamic_index: usize,
518) -> Result<(), SymbolicError> {
519 if config.array_lengths.len() > max_positional_dynamic_index {
520 return Err(SymbolicError::UnsupportedAbi(format!(
521 "symbolic.array_lengths has {} entries but ABI used at most {} positional dynamic leaves",
522 config.array_lengths.len(),
523 max_positional_dynamic_index
524 )));
525 }
526 Ok(())
527}
528
529fn calldata_variant_limit(config: &SymbolicConfig) -> usize {
531 config.path_width().max(1) as usize
532}
533
534fn push_variant<T>(variants: &mut Vec<T>, variant: T, limit: usize) -> Result<(), SymbolicError> {
536 if variants.len() >= limit {
537 return Err(SymbolicError::CalldataVariantLimit(limit));
538 }
539 variants.push(variant);
540 Ok(())
541}
542
543#[derive(Clone, Copy)]
544pub(super) enum DynamicKind {
545 Array,
546 Bytes,
547 String,
548}
549
550impl DynamicKind {
551 pub(super) const fn name(self) -> &'static str {
553 match self {
554 Self::Array => "array",
555 Self::Bytes => "bytes",
556 Self::String => "string",
557 }
558 }
559
560 pub(super) fn default_lengths(self, config: &SymbolicConfig) -> Option<&[u32]> {
562 match self {
563 Self::Array if !config.default_array_lengths.is_empty() => {
564 Some(&config.default_array_lengths)
565 }
566 Self::Bytes | Self::String if !config.default_bytes_lengths.is_empty() => {
567 Some(&config.default_bytes_lengths)
568 }
569 _ => None,
570 }
571 }
572}
573
574pub(super) fn first_dynamic_length(lengths: &[u32], field: &str) -> Result<u32, SymbolicError> {
576 lengths
577 .first()
578 .copied()
579 .ok_or_else(|| SymbolicError::UnsupportedAbi(format!("{field} must not be empty")))
580}
581
582pub(super) fn child_aliases(aliases: &[String], idx: usize) -> Vec<String> {
584 aliases.iter().map(|alias| format!("{alias}_{idx}")).collect()
585}
586
587#[derive(Clone, Debug)]
588pub(super) enum SymbolicAbiValue {
589 Bool { word: SymWord },
590 Uint { bits: usize, word: SymWord },
591 Int { bits: usize, word: SymWord },
592 FixedBytes { bytes: Vec<SymWord>, size: usize },
593 Address { word: SymWord },
594 Bytes { len: SymWord, bytes: Vec<SymWord> },
595 String { bytes: Vec<SymWord> },
596 Array { elements: Vec<Self> },
597 FixedArray { elements: Vec<Self> },
598 Tuple { elements: Vec<Self> },
599}
600
601impl SymbolicAbiValue {
602 pub(super) fn is_dynamic(&self) -> bool {
604 match self {
605 Self::Bool { .. }
606 | Self::Uint { .. }
607 | Self::Int { .. }
608 | Self::FixedBytes { .. }
609 | Self::Address { .. } => false,
610 Self::Bytes { .. } | Self::String { .. } | Self::Array { .. } => true,
611 Self::FixedArray { elements } | Self::Tuple { elements } => {
612 elements.iter().any(Self::is_dynamic)
613 }
614 }
615 }
616
617 pub(super) fn head_size(&self) -> usize {
619 if self.is_dynamic() {
620 32
621 } else {
622 match self {
623 Self::Bool { .. }
624 | Self::Uint { .. }
625 | Self::Int { .. }
626 | Self::FixedBytes { .. }
627 | Self::Address { .. } => 32,
628 Self::FixedArray { elements } | Self::Tuple { elements } => {
629 elements.iter().map(Self::head_size).sum()
630 }
631 Self::Bytes { .. } | Self::String { .. } | Self::Array { .. } => 32,
632 }
633 }
634 }
635
636 pub(super) fn encode_static(&self) -> Vec<SymWord> {
638 match self {
639 Self::Bool { word }
640 | Self::Uint { word, .. }
641 | Self::Int { word, .. }
642 | Self::Address { word } => word_bytes(word.clone()),
643 Self::FixedBytes { bytes, .. } => {
644 let mut out = bytes.clone();
645 out.resize(32, SymWord::zero());
646 out
647 }
648 Self::FixedArray { elements } | Self::Tuple { elements } => {
649 encode_sequence(elements.iter())
650 }
651 Self::Bytes { .. } | Self::String { .. } | Self::Array { .. } => {
652 unreachable!("dynamic ABI value encoded as static")
653 }
654 }
655 }
656
657 pub(super) fn encode_dynamic_body(&self) -> Vec<SymWord> {
659 match self {
660 Self::Bytes { len, bytes } => encode_packed_bytes_with_len(len.clone(), bytes),
661 Self::String { bytes } => {
662 encode_packed_bytes_with_len(SymWord::Concrete(U256::from(bytes.len())), bytes)
663 }
664 Self::Array { elements } => {
665 let mut out = word_bytes(SymWord::Concrete(U256::from(elements.len())));
666 out.extend(encode_sequence(elements.iter()));
667 out
668 }
669 Self::FixedArray { elements } | Self::Tuple { elements } => {
670 encode_sequence(elements.iter())
671 }
672 Self::Bool { .. }
673 | Self::Uint { .. }
674 | Self::Int { .. }
675 | Self::FixedBytes { .. }
676 | Self::Address { .. } => unreachable!("static ABI value encoded as dynamic"),
677 }
678 }
679
680 pub(super) fn model_value(
682 &self,
683 model: &BTreeMap<String, U256>,
684 ) -> Result<DynSolValue, SymbolicError> {
685 Ok(match self {
686 Self::Bool { word } => DynSolValue::Bool(!model_word(word, model)?.is_zero()),
687 Self::Uint { bits, word } => {
688 DynSolValue::Uint(mask_bits(model_word(word, model)?, *bits), *bits)
689 }
690 Self::Int { bits, word } => {
691 DynSolValue::Int(I256::from_raw(model_word(word, model)?), *bits)
692 }
693 Self::FixedBytes { bytes, size } => {
694 let mut word = [0u8; 32];
695 for (idx, byte) in bytes.iter().enumerate() {
696 word[idx] = model_word(byte, model)?.to::<u8>();
697 }
698 DynSolValue::FixedBytes(B256::from(word), *size)
699 }
700 Self::Address { word } => {
701 DynSolValue::Address(word_to_address(model_word(word, model)?))
702 }
703 Self::Bytes { len, bytes } => {
704 let len = model_word(len, model)?;
705 let len = u256_to_usize(len)
706 .filter(|len| *len <= bytes.len())
707 .ok_or_else(|| SymbolicError::Solver("invalid symbolic bytes length".into()))?;
708 let mut bytes = model_bytes(bytes, model)?;
709 bytes.truncate(len);
710 DynSolValue::Bytes(bytes)
711 }
712 Self::String { bytes } => {
713 let bytes = model_bytes(bytes, model)?;
714 let value = String::from_utf8(bytes).map_err(|err| {
715 SymbolicError::Solver(format!("invalid symbolic string model: {err}"))
716 })?;
717 DynSolValue::String(value)
718 }
719 Self::Array { elements } => DynSolValue::Array(
720 elements
721 .iter()
722 .map(|value| value.model_value(model))
723 .collect::<Result<Vec<_>, _>>()?,
724 ),
725 Self::FixedArray { elements } => DynSolValue::FixedArray(
726 elements
727 .iter()
728 .map(|value| value.model_value(model))
729 .collect::<Result<Vec<_>, _>>()?,
730 ),
731 Self::Tuple { elements } => DynSolValue::Tuple(
732 elements
733 .iter()
734 .map(|value| value.model_value(model))
735 .collect::<Result<Vec<_>, _>>()?,
736 ),
737 })
738 }
739}
740
741pub(super) fn encode_sequence<'a>(
743 values: impl IntoIterator<Item = &'a SymbolicAbiValue>,
744) -> Vec<SymWord> {
745 let values = values.into_iter().collect::<Vec<_>>();
746 let head_size = values.iter().map(|value| value.head_size()).sum::<usize>();
747 let mut head = Vec::with_capacity(head_size);
748 let mut tail = Vec::new();
749
750 for value in values {
751 if value.is_dynamic() {
752 head.extend(word_bytes(SymWord::Concrete(U256::from(head_size + tail.len()))));
753 tail.extend(value.encode_dynamic_body());
754 } else {
755 head.extend(value.encode_static());
756 }
757 }
758
759 head.extend(tail);
760 head
761}
762
763pub(super) fn encode_packed_bytes_with_len(len: SymWord, bytes: &[SymWord]) -> Vec<SymWord> {
765 let mut out = word_bytes(len);
766 out.extend(bytes.iter().cloned());
767 out.resize(32 + bytes.len().next_multiple_of(32), SymWord::zero());
768 out
769}