1use crate::util::condition::{
2 resolve_num_value_decimal, resolve_num_value_int, resolve_num_value_uint,
3 resolve_query_expr_bool, resolve_query_expr_decimal, resolve_query_expr_int,
4 resolve_query_expr_string, resolve_query_expr_uint, resolve_ref_bool,
5};
6use crate::ContractError;
7use cosmwasm_schema::serde::de::DeserializeOwned;
8use cosmwasm_schema::serde::Serialize;
9use cosmwasm_std::{
10 Binary, CosmosMsg, Decimal256, Deps, Env, QueryRequest, Uint128, Uint256, WasmQuery,
11};
12use std::str::FromStr;
13
14use warp_controller_pkg::job::{ExternalInput, JobStatus};
15use warp_resolver_pkg::variable::{QueryExpr, UpdateFnValue, Variable, VariableKind};
16
17pub fn hydrate_vars(
18 deps: Deps,
19 env: Env,
20 vars: Vec<Variable>,
21 external_inputs: Option<Vec<ExternalInput>>,
22) -> Result<Vec<Variable>, ContractError> {
23 let mut hydrated_vars = vec![];
24
25 for var in vars {
26 let hydrated_var = match var {
27 Variable::Static(mut v) => {
28 v.value = replace_in_string(v.value, &hydrated_vars)?;
29 Variable::Static(v)
30 }
31 Variable::External(mut v) => {
32 if v.reinitialize || v.value.is_none() {
33 match external_inputs {
34 None => {
35 if v.value.is_none() {
36 return Err(ContractError::HydrationError {
37 msg: "External input value is none.".to_string(),
38 });
39 }
40 Variable::External(v)
41 }
42 Some(ref input) => {
43 let idx = input.iter().position(|i| i.name == v.name);
44 v.value = match idx {
45 None => {
46 return Err(ContractError::HydrationError {
47 msg: "External input variable not found.".to_string(),
48 })
49 }
50 Some(i) => Some(input[i].input.clone()),
51 };
52 Variable::External(v)
53 }
54 }
55 } else {
56 if v.value.is_none() {
57 return Err(ContractError::HydrationError {
58 msg: "External value is none.".to_string(),
59 });
60 }
61 Variable::External(v)
62 }
63 }
64 Variable::Query(mut v) => {
65 if v.reinitialize || v.value.is_none() {
66 v.init_fn = replace_references(v.init_fn, &hydrated_vars)?;
67
68 match v.kind {
69 VariableKind::String => {
70 v.value = Some(
71 resolve_query_expr_string(deps, env.clone(), v.init_fn.clone())?
73 .to_string(),
74 )
75 }
76 VariableKind::Uint => {
77 v.value = Some(
78 resolve_query_expr_uint(deps, env.clone(), v.init_fn.clone())?
79 .to_string(),
80 )
81 }
82 VariableKind::Int => {
83 v.value = Some(
84 resolve_query_expr_int(deps, env.clone(), v.init_fn.clone())?
85 .to_string(),
86 )
87 }
88 VariableKind::Decimal => {
89 v.value = Some(
90 resolve_query_expr_decimal(deps, env.clone(), v.init_fn.clone())?
91 .to_string(),
92 )
93 }
94 VariableKind::Timestamp => {
95 v.value = Some(
96 resolve_query_expr_int(deps, env.clone(), v.init_fn.clone())?
97 .to_string(),
98 )
99 }
100 VariableKind::Bool => {
101 v.value = Some(
102 resolve_query_expr_bool(deps, env.clone(), v.init_fn.clone())?
103 .to_string(),
104 )
105 }
106 VariableKind::Amount => {
107 v.value = Some(
108 resolve_query_expr_uint(deps, env.clone(), v.init_fn.clone())?
109 .to_string(),
110 )
111 }
112 VariableKind::Asset => {
113 v.value = Some(
114 resolve_query_expr_string(deps, env.clone(), v.init_fn.clone())?
115 .to_string(),
116 )
117 }
118 VariableKind::Json => {
119 v.value = Some(
120 resolve_query_expr_string(deps, env.clone(), v.init_fn.clone())?
121 .to_string(),
122 )
123 }
124 }
125 }
126 if v.value.is_none() {
127 return Err(ContractError::Unauthorized {});
128 }
129 Variable::Query(v)
130 }
131 };
132 hydrated_vars.push(hydrated_var);
133 }
134 Ok(hydrated_vars)
135}
136
137pub fn hydrate_msgs(msgs: String, vars: Vec<Variable>) -> Result<Vec<CosmosMsg>, ContractError> {
138 let mut replaced_msgs = msgs;
139 for var in &vars {
140 let (name, replacement) = get_replacement_in_struct(var)?;
141 replaced_msgs =
142 replaced_msgs.replace(&format!("\"$warp.variable.{}\"", name), &replacement);
143 if replacement.contains("$warp.variable") {
144 return Err(ContractError::HydrationError {
145 msg: "Attempt to inject warp variable.".to_string(),
146 });
147 }
148 }
149
150 Ok(serde_json_wasm::from_str::<Vec<CosmosMsg>>(&replaced_msgs)?)
151}
152
153fn get_replacement_in_struct(var: &Variable) -> Result<(String, String), ContractError> {
154 let (name, replacement) = match var {
155 Variable::Static(v) => (v.name.clone(), {
156 match v.kind {
157 VariableKind::String => format!(
158 "\"{}\"",
159 match v.encode {
160 true => {
161 base64::encode(v.value.clone())
162 }
163 false => v.value.clone(),
164 }
165 ),
166 VariableKind::Uint => format!(
167 "\"{}\"",
168 match v.encode {
169 true => {
170 base64::encode(v.value.clone())
171 }
172 false => v.value.clone(),
173 }
174 ),
175 VariableKind::Int => match v.encode {
176 true => {
177 format!("\"{}\"", base64::encode(v.value.clone()))
178 }
179 false => v.value.clone(),
180 },
181 VariableKind::Decimal => format!(
182 "\"{}\"",
183 match v.encode {
184 true => {
185 base64::encode(v.value.clone())
186 }
187 false => v.value.clone(),
188 }
189 ),
190 VariableKind::Timestamp => match v.encode {
191 true => {
192 format!("\"{}\"", base64::encode(v.value.clone()))
193 }
194 false => v.value.clone(),
195 },
196 VariableKind::Bool => match v.encode {
197 true => {
198 format!("\"{}\"", base64::encode(v.value.clone()))
199 }
200 false => v.value.clone(),
201 },
202 VariableKind::Amount => format!(
203 "\"{}\"",
204 match v.encode {
205 true => {
206 base64::encode(v.value.clone())
207 }
208 false => v.value.clone(),
209 }
210 ),
211 VariableKind::Asset => format!(
212 "\"{}\"",
213 match v.encode {
214 true => {
215 base64::encode(v.value.clone())
216 }
217 false => v.value.clone(),
218 }
219 ),
220 VariableKind::Json => match v.encode {
221 true => {
222 format!("\"{}\"", base64::encode(v.value.clone()))
223 }
224 false => v.value.clone(),
225 },
226 }
227 }),
228 Variable::External(v) => match v.value.clone() {
229 None => {
230 return Err(ContractError::HydrationError {
231 msg: "External msg value is none.".to_string(),
232 });
233 }
234 Some(val) => (v.name.clone(), {
235 match v.kind {
236 VariableKind::String => format!(
237 "\"{}\"",
238 match v.encode {
239 true => {
240 base64::encode(val)
241 }
242 false => val,
243 }
244 ),
245 VariableKind::Uint => format!(
246 "\"{}\"",
247 match v.encode {
248 true => {
249 base64::encode(val)
250 }
251 false => val,
252 }
253 ),
254 VariableKind::Int => match v.encode {
255 true => {
256 format!("\"{}\"", base64::encode(val))
257 }
258 false => val,
259 },
260 VariableKind::Decimal => format!(
261 "\"{}\"",
262 match v.encode {
263 true => {
264 base64::encode(val)
265 }
266 false => val,
267 }
268 ),
269 VariableKind::Timestamp => match v.encode {
270 true => {
271 format!("\"{}\"", base64::encode(val))
272 }
273 false => val,
274 },
275 VariableKind::Bool => match v.encode {
276 true => {
277 format!("\"{}\"", base64::encode(val))
278 }
279 false => val,
280 },
281 VariableKind::Amount => format!(
282 "\"{}\"",
283 match v.encode {
284 true => {
285 base64::encode(val)
286 }
287 false => val,
288 }
289 ),
290 VariableKind::Asset => format!(
291 "\"{}\"",
292 match v.encode {
293 true => {
294 base64::encode(val)
295 }
296 false => val,
297 }
298 ),
299 VariableKind::Json => match v.encode {
300 true => {
301 format!("\"{}\"", base64::encode(val))
302 }
303 false => val,
304 },
305 }
306 }),
307 },
308 Variable::Query(v) => match v.value.clone() {
309 None => {
310 return Err(ContractError::HydrationError {
311 msg: "Query msg value is none.".to_string(),
312 });
313 }
314 Some(val) => (v.name.clone(), {
315 match v.kind {
316 VariableKind::String => format!(
317 "\"{}\"",
318 match v.encode {
319 true => {
320 base64::encode(val)
321 }
322 false => val,
323 }
324 ),
325 VariableKind::Uint => format!(
326 "\"{}\"",
327 match v.encode {
328 true => {
329 base64::encode(val)
330 }
331 false => val,
332 }
333 ),
334 VariableKind::Int => match v.encode {
335 true => {
336 format!("\"{}\"", base64::encode(val))
337 }
338 false => val,
339 },
340 VariableKind::Decimal => format!(
341 "\"{}\"",
342 match v.encode {
343 true => {
344 base64::encode(val)
345 }
346 false => val,
347 }
348 ),
349 VariableKind::Timestamp => match v.encode {
350 true => {
351 format!("\"{}\"", base64::encode(val))
352 }
353 false => val,
354 },
355 VariableKind::Bool => match v.encode {
356 true => {
357 format!("\"{}\"", base64::encode(val))
358 }
359 false => val,
360 },
361 VariableKind::Amount => format!(
362 "\"{}\"",
363 match v.encode {
364 true => {
365 base64::encode(val)
366 }
367 false => val,
368 }
369 ),
370 VariableKind::Asset => format!(
371 "\"{}\"",
372 match v.encode {
373 true => {
374 base64::encode(val)
375 }
376 false => val,
377 }
378 ),
379 VariableKind::Json => match v.encode {
380 true => {
381 format!("\"{}\"", base64::encode(val))
382 }
383 false => val,
384 },
385 }
386 }),
387 },
388 };
389
390 Ok((name, replacement))
391}
392
393fn get_replacement_in_string(var: &Variable) -> Result<(String, String), ContractError> {
394 let (name, replacement) = match var {
395 Variable::Static(v) => (
396 v.name.clone(),
397 match v.encode {
398 true => base64::encode(v.value.clone()),
399 false => v.value.clone(),
400 },
401 ),
402 Variable::External(v) => match v.value.clone() {
403 None => {
404 return Err(ContractError::HydrationError {
405 msg: "External msg value is none.".to_string(),
406 });
407 }
408 Some(val) => (
409 v.name.clone(),
410 match v.encode {
411 true => base64::encode(val),
412 false => val,
413 },
414 ),
415 },
416 Variable::Query(v) => match v.value.clone() {
417 None => {
418 return Err(ContractError::HydrationError {
419 msg: "Query msg value is none.".to_string(),
420 });
421 }
422 Some(val) => (
423 v.name.clone(),
424 match v.encode {
425 true => base64::encode(val),
426 false => val,
427 },
428 ),
429 },
430 };
431
432 Ok((name, replacement))
433}
434
435fn replace_references(mut expr: QueryExpr, vars: &[Variable]) -> Result<QueryExpr, ContractError> {
436 match &mut expr.query {
437 QueryRequest::Wasm(WasmQuery::Smart { msg, contract_addr }) => {
438 *msg = replace_in_binary(msg, vars)?;
439 *contract_addr = replace_in_string(contract_addr.to_string(), vars)?;
440 }
441 QueryRequest::Wasm(WasmQuery::Raw { key, contract_addr }) => {
442 *key = replace_in_binary(key, vars)?;
443 *contract_addr = replace_in_string(contract_addr.to_string(), vars)?;
444 }
445 _ => expr.query = replace_in_struct(&expr.query, vars)?,
446 }
447
448 Ok(expr)
449}
450
451fn replace_in_binary(binary_str: &Binary, vars: &[Variable]) -> Result<Binary, ContractError> {
452 let decoded =
453 base64::decode(binary_str.to_string()).map_err(|_| ContractError::HydrationError {
454 msg: "Failed to decode Base64.".to_string(),
455 })?;
456 let decoded_string = String::from_utf8(decoded).map_err(|_| ContractError::HydrationError {
457 msg: "Failed to convert from UTF8.".to_string(),
458 })?;
459
460 let updated_string = replace_in_struct_string(decoded_string, vars)?;
461
462 Ok(Binary::from(updated_string.as_bytes()))
463}
464
465fn replace_in_struct<T: Serialize + DeserializeOwned>(
466 struct_val: &T,
467 vars: &[Variable],
468) -> Result<T, ContractError> {
469 let struct_as_json =
470 serde_json_wasm::to_string(&struct_val).map_err(|_| ContractError::HydrationError {
471 msg: "Failed to convert struct to JSON.".to_string(),
472 })?;
473 let updated_struct_as_json = replace_in_struct_string(struct_as_json, vars)?;
474 serde_json_wasm::from_str(&updated_struct_as_json).map_err(|_| ContractError::HydrationError {
475 msg: "Failed to convert JSON back to struct.".to_string(),
476 })
477}
478
479fn replace_in_struct_string(value: String, vars: &[Variable]) -> Result<String, ContractError> {
480 let mut replaced_value = value;
481
482 for var in vars {
483 let (name, replacement) = get_replacement_in_struct(var)?;
484 replaced_value =
485 replaced_value.replace(&format!("\"$warp.variable.{}\"", name), &replacement);
486 }
487
488 Ok(replaced_value)
489}
490
491fn replace_in_string(value: String, vars: &[Variable]) -> Result<String, ContractError> {
492 let mut replaced_value = value;
493
494 for var in vars {
495 let (name, replacement) = get_replacement_in_string(var)?;
496 replaced_value = replaced_value.replace(&format!("$warp.variable.{}", name), &replacement);
497 }
498
499 Ok(replaced_value)
500}
501
502pub fn msgs_valid(msgs: &str, vars: &Vec<Variable>) -> Result<bool, ContractError> {
503 let mut replaced_msgs = msgs.to_owned();
504 for var in vars {
505 let (name, replacement) = match var {
506 Variable::Static(v) => (
507 v.name.clone(),
508 match v.kind {
509 VariableKind::String => "\"test\"",
510 VariableKind::Uint => "\"0\"",
511 VariableKind::Int => "0",
512 VariableKind::Decimal => "\"0.0\"",
513 VariableKind::Timestamp => "0",
514 VariableKind::Bool => "true",
515 VariableKind::Amount => "\"0\"",
516 VariableKind::Asset => "\"test\"",
517 VariableKind::Json => "true",
518 },
519 ),
520 Variable::External(v) => (
521 v.name.clone(),
522 match v.kind {
523 VariableKind::String => "\"test\"",
524 VariableKind::Uint => "\"0\"",
525 VariableKind::Int => "0",
526 VariableKind::Decimal => "\"0.0\"",
527 VariableKind::Timestamp => "0",
528 VariableKind::Bool => "true",
529 VariableKind::Amount => "\"0\"",
530 VariableKind::Asset => "\"test\"",
531 VariableKind::Json => "true",
532 },
533 ),
534 Variable::Query(v) => (
535 v.name.clone(),
536 match v.kind {
537 VariableKind::String => "\"test\"",
538 VariableKind::Uint => "\"0\"",
539 VariableKind::Int => "0",
540 VariableKind::Decimal => "\"0.0\"",
541 VariableKind::Timestamp => "0",
542 VariableKind::Bool => "true",
543 VariableKind::Amount => "\"0\"",
544 VariableKind::Asset => "\"test\"",
545 VariableKind::Json => "true",
546 },
547 ),
548 };
549 if replacement.contains("$warp.variable") {
550 return Err(ContractError::HydrationError {
551 msg: "Attempt to inject warp variable.".to_string(),
552 });
553 }
554 let replacement_with_encode = match var {
555 Variable::Static(v) => match v.encode {
556 true => format!("\"{}\"", base64::encode(replacement)),
557 false => replacement.to_string(),
558 },
559 Variable::External(v) => match v.encode {
560 true => format!("\"{}\"", base64::encode(replacement)),
561 false => replacement.to_string(),
562 },
563 Variable::Query(v) => match v.encode {
564 true => format!("\"{}\"", base64::encode(replacement)),
565 false => replacement.to_string(),
566 },
567 };
568 replaced_msgs = replaced_msgs.replace(
569 &format!("\"$warp.variable.{}\"", name),
570 &replacement_with_encode,
571 );
572 }
573
574 let _msgs = serde_json_wasm::from_str::<Vec<CosmosMsg>>(&replaced_msgs)?;
575
576 Ok(true)
577}
578
579pub fn apply_var_fn(
580 deps: Deps,
581 env: Env,
582 vars: Vec<Variable>,
583 status: JobStatus,
584) -> Result<String, ContractError> {
585 let mut res = vec![];
586 for var in vars.clone() {
587 match var {
588 Variable::Static(mut v) => {
589 match v.update_fn.clone() {
590 None => (),
591 Some(update_fn) => match status {
592 JobStatus::Pending => {
593 return Err(ContractError::FunctionError {
594 msg: "Static job status pending.".to_string(),
595 })
596 }
597 JobStatus::Executed => match update_fn.on_success {
598 None => (),
599 Some(on_success) => match on_success {
600 UpdateFnValue::Uint(nv) => {
601 if v.kind != VariableKind::Uint {
602 return Err(ContractError::FunctionError {
603 msg: "Static Uint function mismatch.".to_string(),
604 });
605 }
606 v.value = resolve_num_value_uint(deps, env.clone(), nv, &vars)?
607 .to_string();
608 }
609 UpdateFnValue::Int(nv) => {
610 if v.kind != VariableKind::Int {
611 return Err(ContractError::FunctionError {
612 msg: "Static Int function mismatch.".to_string(),
613 });
614 }
615 v.value = resolve_num_value_int(deps, env.clone(), nv, &vars)?
616 .to_string();
617 }
618 UpdateFnValue::Decimal(nv) => {
619 if v.kind != VariableKind::Decimal {
620 return Err(ContractError::FunctionError {
621 msg: "Static Decimal function mismatch.".to_string(),
622 });
623 }
624 v.value =
625 resolve_num_value_decimal(deps, env.clone(), nv, &vars)?
626 .to_string();
627 }
628 UpdateFnValue::Timestamp(nv) => {
629 if v.kind != VariableKind::Int {
630 return Err(ContractError::FunctionError {
631 msg: "Static Timestamp function mismatch.".to_string(),
632 });
633 }
634 v.value = resolve_num_value_int(deps, env.clone(), nv, &vars)?
635 .to_string();
636 }
637 UpdateFnValue::BlockHeight(nv) => {
638 if v.kind != VariableKind::Int {
639 return Err(ContractError::FunctionError {
640 msg: "Static BlockHeight function mismatch."
641 .to_string(),
642 });
643 }
644 v.value = resolve_num_value_int(deps, env.clone(), nv, &vars)?
645 .to_string();
646 }
647 UpdateFnValue::Bool(val) => {
648 if v.kind != VariableKind::Bool {
649 return Err(ContractError::FunctionError {
650 msg: "Static Bool function mismatch.".to_string(),
651 });
652 }
653 v.value = resolve_ref_bool(deps, env.clone(), val, &vars)?
654 .to_string();
655 }
656 },
657 },
658 JobStatus::Failed => match update_fn.on_error {
659 None => (),
660 Some(on_success) => match on_success {
661 UpdateFnValue::Uint(nv) => {
662 if v.kind != VariableKind::Uint {
663 return Err(ContractError::FunctionError {
664 msg: "Static Uint function mismatch.".to_string(),
665 });
666 }
667 v.value = resolve_num_value_uint(deps, env.clone(), nv, &vars)?
668 .to_string();
669 }
670 UpdateFnValue::Int(nv) => {
671 if v.kind != VariableKind::Int {
672 return Err(ContractError::FunctionError {
673 msg: "Static Int function mismatch.".to_string(),
674 });
675 }
676 v.value = resolve_num_value_int(deps, env.clone(), nv, &vars)?
677 .to_string();
678 }
679 UpdateFnValue::Decimal(nv) => {
680 if v.kind != VariableKind::Decimal {
681 return Err(ContractError::FunctionError {
682 msg: "Static Uint function mismatch.".to_string(),
683 });
684 }
685 v.value =
686 resolve_num_value_decimal(deps, env.clone(), nv, &vars)?
687 .to_string()
688 }
689 UpdateFnValue::Timestamp(nv) => {
690 if v.kind != VariableKind::Int {
691 return Err(ContractError::FunctionError {
692 msg: "Static Timestamp function mismatch.".to_string(),
693 });
694 }
695 v.value = resolve_num_value_int(deps, env.clone(), nv, &vars)?
696 .to_string();
697 }
698 UpdateFnValue::BlockHeight(nv) => {
699 if v.kind != VariableKind::Int {
700 return Err(ContractError::FunctionError {
701 msg: "Static BlockHeight function mismatch."
702 .to_string(),
703 });
704 }
705 v.value = resolve_num_value_int(deps, env.clone(), nv, &vars)?
706 .to_string();
707 }
708 UpdateFnValue::Bool(val) => {
709 if v.kind != VariableKind::Bool {
710 return Err(ContractError::FunctionError {
711 msg: "Static Bool function mismatch.".to_string(),
712 });
713 }
714 v.value = resolve_ref_bool(deps, env.clone(), val, &vars)?
715 .to_string();
716 }
717 },
718 },
719 _ => {
720 return Err(ContractError::FunctionError {
721 msg: "Static status not supported.".to_string(),
722 })
723 }
724 },
725 }
726 res.push(Variable::Static(v));
727 }
728 Variable::External(mut v) => {
729 match v.update_fn.clone() {
730 None => (),
731 Some(update_fn) => match status {
732 JobStatus::Pending => {
733 return Err(ContractError::FunctionError {
734 msg: "External job status pending.".to_string(),
735 })
736 }
737 JobStatus::Executed => match update_fn.on_success {
738 None => (),
739 Some(on_success) => match on_success {
740 UpdateFnValue::Uint(nv) => {
741 if v.kind != VariableKind::Uint {
742 return Err(ContractError::FunctionError {
743 msg: "External Uint function mismatch.".to_string(),
744 });
745 }
746 v.value = Some(
747 resolve_num_value_uint(deps, env.clone(), nv, &vars)?
748 .to_string(),
749 )
750 }
751 UpdateFnValue::Int(nv) => {
752 if v.kind != VariableKind::Int {
753 return Err(ContractError::FunctionError {
754 msg: "External Int function mismatch.".to_string(),
755 });
756 }
757 v.value = Some(
758 resolve_num_value_int(deps, env.clone(), nv, &vars)?
759 .to_string(),
760 )
761 }
762 UpdateFnValue::Decimal(nv) => {
763 if v.kind != VariableKind::Decimal {
764 return Err(ContractError::FunctionError {
765 msg: "External Decimal function mismatch.".to_string(),
766 });
767 }
768 v.value = Some(
769 resolve_num_value_decimal(deps, env.clone(), nv, &vars)?
770 .to_string(),
771 )
772 }
773 UpdateFnValue::Timestamp(nv) => {
774 if v.kind != VariableKind::Int {
775 return Err(ContractError::FunctionError {
776 msg: "External Timestamp function mismatch."
777 .to_string(),
778 });
779 }
780 v.value = Some(
781 resolve_num_value_int(deps, env.clone(), nv, &vars)?
782 .to_string(),
783 )
784 }
785 UpdateFnValue::BlockHeight(nv) => {
786 if v.kind != VariableKind::Int {
787 return Err(ContractError::FunctionError {
788 msg: "External BlockHeight function mismatch."
789 .to_string(),
790 });
791 }
792 v.value = Some(
793 resolve_num_value_int(deps, env.clone(), nv, &vars)?
794 .to_string(),
795 )
796 }
797 UpdateFnValue::Bool(val) => {
798 if v.kind != VariableKind::Bool {
799 return Err(ContractError::FunctionError {
800 msg: "External Bool function mismatch.".to_string(),
801 });
802 }
803 v.value = Some(
804 resolve_ref_bool(deps, env.clone(), val, &vars)?
805 .to_string(),
806 )
807 }
808 },
809 },
810 JobStatus::Failed => match update_fn.on_error {
811 None => (),
812 Some(on_success) => match on_success {
813 UpdateFnValue::Uint(nv) => {
814 if v.kind != VariableKind::Uint {
815 return Err(ContractError::FunctionError {
816 msg: "External Uint function mismatch.".to_string(),
817 });
818 }
819 v.value = Some(
820 resolve_num_value_uint(deps, env.clone(), nv, &vars)?
821 .to_string(),
822 )
823 }
824 UpdateFnValue::Int(nv) => {
825 if v.kind != VariableKind::Int {
826 return Err(ContractError::FunctionError {
827 msg: "External Int function mismatch.".to_string(),
828 });
829 }
830 v.value = Some(
831 resolve_num_value_int(deps, env.clone(), nv, &vars)?
832 .to_string(),
833 )
834 }
835 UpdateFnValue::Decimal(nv) => {
836 if v.kind != VariableKind::Decimal {
837 return Err(ContractError::FunctionError {
838 msg: "External Decimal function mismatch.".to_string(),
839 });
840 }
841 v.value = Some(
842 resolve_num_value_decimal(deps, env.clone(), nv, &vars)?
843 .to_string(),
844 )
845 }
846 UpdateFnValue::Timestamp(nv) => {
847 if v.kind != VariableKind::Int {
848 return Err(ContractError::FunctionError {
849 msg: "External Timestamp function mismatch."
850 .to_string(),
851 });
852 }
853 v.value = Some(
854 resolve_num_value_int(deps, env.clone(), nv, &vars)?
855 .to_string(),
856 )
857 }
858 UpdateFnValue::BlockHeight(nv) => {
859 if v.kind != VariableKind::Int {
860 return Err(ContractError::FunctionError {
861 msg: "External BlockHeight function mismatch."
862 .to_string(),
863 });
864 }
865 v.value = Some(
866 resolve_num_value_int(deps, env.clone(), nv, &vars)?
867 .to_string(),
868 )
869 }
870 UpdateFnValue::Bool(val) => {
871 if v.kind != VariableKind::Bool {
872 return Err(ContractError::FunctionError {
873 msg: "External Bool function mismatch.".to_string(),
874 });
875 }
876 v.value = Some(
877 resolve_ref_bool(deps, env.clone(), val, &vars)?
878 .to_string(),
879 )
880 }
881 },
882 },
883 _ => {
884 return Err(ContractError::FunctionError {
885 msg: "External status not supported.".to_string(),
886 })
887 }
888 },
889 }
890 res.push(Variable::External(v));
891 }
892 Variable::Query(mut v) => {
893 match v.update_fn.clone() {
894 None => (),
895 Some(update_fn) => match status {
896 JobStatus::Pending => {
897 return Err(ContractError::FunctionError {
898 msg: "Query job status pending.".to_string(),
899 })
900 }
901 JobStatus::Executed => match update_fn.on_success {
902 None => (),
903 Some(on_success) => match on_success {
904 UpdateFnValue::Uint(nv) => {
905 if v.kind != VariableKind::Uint {
906 return Err(ContractError::FunctionError {
907 msg: "Query Uint function mismatch.".to_string(),
908 });
909 }
910 v.value = Some(
911 resolve_num_value_uint(deps, env.clone(), nv, &vars)?
912 .to_string(),
913 )
914 }
915 UpdateFnValue::Int(nv) => {
916 if v.kind != VariableKind::Int {
917 return Err(ContractError::FunctionError {
918 msg: "Query Int function mismatch.".to_string(),
919 });
920 }
921 v.value = Some(
922 resolve_num_value_int(deps, env.clone(), nv, &vars)?
923 .to_string(),
924 )
925 }
926 UpdateFnValue::Decimal(nv) => {
927 if v.kind != VariableKind::Decimal {
928 return Err(ContractError::FunctionError {
929 msg: "Query Decimal function mismatch.".to_string(),
930 });
931 }
932 v.value = Some(
933 resolve_num_value_decimal(deps, env.clone(), nv, &vars)?
934 .to_string(),
935 )
936 }
937 UpdateFnValue::Timestamp(nv) => {
938 if v.kind != VariableKind::Int {
939 return Err(ContractError::FunctionError {
940 msg: "Query Timestamp function mismatch.".to_string(),
941 });
942 }
943 v.value = Some(
944 resolve_num_value_int(deps, env.clone(), nv, &vars)?
945 .to_string(),
946 )
947 }
948 UpdateFnValue::BlockHeight(nv) => {
949 if v.kind != VariableKind::Int {
950 return Err(ContractError::FunctionError {
951 msg: "Query Blockheighht function mismatch."
952 .to_string(),
953 });
954 }
955 v.value = Some(
956 resolve_num_value_int(deps, env.clone(), nv, &vars)?
957 .to_string(),
958 )
959 }
960 UpdateFnValue::Bool(val) => {
961 if v.kind != VariableKind::Bool {
962 return Err(ContractError::FunctionError {
963 msg: "Query Bool function mismatch.".to_string(),
964 });
965 }
966 v.value = Some(
967 resolve_ref_bool(deps, env.clone(), val, &vars)?
968 .to_string(),
969 )
970 }
971 },
972 },
973 JobStatus::Failed => match update_fn.on_error {
974 None => (),
975 Some(on_success) => match on_success {
976 UpdateFnValue::Uint(nv) => {
977 if v.kind != VariableKind::Uint {
978 return Err(ContractError::FunctionError {
979 msg: "Query Uint function mismatch.".to_string(),
980 });
981 }
982 v.value = Some(
983 resolve_num_value_uint(deps, env.clone(), nv, &vars)?
984 .to_string(),
985 )
986 }
987 UpdateFnValue::Int(nv) => {
988 if v.kind != VariableKind::Int {
989 return Err(ContractError::FunctionError {
990 msg: "Query Int function mismatch.".to_string(),
991 });
992 }
993 v.value = Some(
994 resolve_num_value_int(deps, env.clone(), nv, &vars)?
995 .to_string(),
996 )
997 }
998 UpdateFnValue::Decimal(nv) => {
999 if v.kind != VariableKind::Decimal {
1000 return Err(ContractError::FunctionError {
1001 msg: "Query Decimal function mismatch.".to_string(),
1002 });
1003 }
1004 v.value = Some(
1005 resolve_num_value_decimal(deps, env.clone(), nv, &vars)?
1006 .to_string(),
1007 )
1008 }
1009 UpdateFnValue::Timestamp(nv) => {
1010 if v.kind != VariableKind::Int {
1011 return Err(ContractError::FunctionError {
1012 msg: "Query Timestamp function mismatch.".to_string(),
1013 });
1014 }
1015 v.value = Some(
1016 resolve_num_value_int(deps, env.clone(), nv, &vars)?
1017 .to_string(),
1018 )
1019 }
1020 UpdateFnValue::BlockHeight(nv) => {
1021 if v.kind != VariableKind::Int {
1022 return Err(ContractError::FunctionError {
1023 msg: "Query BlockHeight function mismatch.".to_string(),
1024 });
1025 }
1026 v.value = Some(
1027 resolve_num_value_int(deps, env.clone(), nv, &vars)?
1028 .to_string(),
1029 )
1030 }
1031 UpdateFnValue::Bool(val) => {
1032 if v.kind != VariableKind::Bool {
1033 return Err(ContractError::FunctionError {
1034 msg: "Query Bool function mismatch.".to_string(),
1035 });
1036 }
1037 v.value = Some(
1038 resolve_ref_bool(deps, env.clone(), val, &vars)?
1039 .to_string(),
1040 )
1041 }
1042 },
1043 },
1044 _ => {
1045 return Err(ContractError::FunctionError {
1046 msg: "Query status not supported.".to_string(),
1047 })
1048 }
1049 },
1050 }
1051 res.push(Variable::Query(v));
1052 }
1053 }
1054 }
1055 Ok(serde_json_wasm::to_string(&res)?)
1056}
1057
1058pub fn get_var(name: String, vars: &Vec<Variable>) -> Result<&Variable, ContractError> {
1059 for var in vars {
1060 let n = match var {
1061 Variable::Static(v) => v.name.clone(),
1062 Variable::External(v) => v.name.clone(),
1063 Variable::Query(v) => v.name.clone(),
1064 };
1065 if format!("$warp.variable.{}", n) == name {
1066 return Ok(var);
1067 }
1068 }
1069 Err(ContractError::VariableNotFound { name })
1070}
1071
1072pub fn has_duplicates(vars: &Vec<Variable>) -> bool {
1073 for i in 0..vars.len() {
1074 for j in i..vars.len() {
1075 if i != j {
1076 match vars[i].clone() {
1077 Variable::Static(vari) => match vars[j].clone() {
1078 Variable::Static(varj) => {
1079 if vari.name == varj.name {
1080 return true;
1081 }
1082 }
1083 Variable::External(varj) => {
1084 if vari.name == varj.name {
1085 return true;
1086 }
1087 }
1088 Variable::Query(varj) => {
1089 if vari.name == varj.name {
1090 return true;
1091 }
1092 }
1093 },
1094 Variable::External(vari) => match vars[j].clone() {
1095 Variable::Static(varj) => {
1096 if vari.name == varj.name {
1097 return true;
1098 }
1099 }
1100 Variable::External(varj) => {
1101 if vari.name == varj.name {
1102 return true;
1103 }
1104 }
1105 Variable::Query(varj) => {
1106 if vari.name == varj.name {
1107 return true;
1108 }
1109 }
1110 },
1111 Variable::Query(vari) => match vars[j].clone() {
1112 Variable::Static(varj) => {
1113 if vari.name == varj.name {
1114 return true;
1115 }
1116 }
1117 Variable::External(varj) => {
1118 if vari.name == varj.name {
1119 return true;
1120 }
1121 }
1122 Variable::Query(varj) => {
1123 if vari.name == varj.name {
1124 return true;
1125 }
1126 }
1127 },
1128 }
1129 }
1130 }
1131 }
1132 false
1133}
1134
1135pub fn string_vars_in_vector(vars: &Vec<Variable>, s: &String) -> bool {
1136 let mut s = s.to_owned();
1137 for var in vars {
1138 let name = get_var_name(var);
1139 s = s.replace(format!("$warp.variable.{}", name).as_str(), "VAR_CHECKED")
1140 }
1141 if s.contains("$warp.variable.") {
1142 return false;
1143 }
1144 true
1145}
1146
1147fn get_var_name(var: &Variable) -> String {
1148 match var.clone() {
1149 Variable::Static(v) => v.name,
1150 Variable::External(v) => v.name,
1151 Variable::Query(v) => v.name,
1152 }
1153}
1154
1155pub fn vars_valid(vars: &Vec<Variable>) -> bool {
1156 for var in vars {
1157 match var {
1158 Variable::Static(v) => match v.kind {
1159 VariableKind::String => {}
1160 VariableKind::Uint => {
1161 if Uint256::from_str(&v.value).is_err() {
1162 return false;
1163 }
1164 }
1165 VariableKind::Int => {
1166 if i128::from_str(&v.value).is_err() {
1167 return false;
1168 }
1169 }
1170 VariableKind::Decimal => {
1171 if Decimal256::from_str(&v.value).is_err() {
1172 return false;
1173 }
1174 }
1175 VariableKind::Timestamp => {
1176 if i128::from_str(&v.value).is_err() {
1177 return false;
1178 }
1179 }
1180 VariableKind::Bool => {
1181 if bool::from_str(&v.value).is_err() {
1182 return false;
1183 }
1184 }
1185 VariableKind::Amount => {
1186 if Uint128::from_str(&v.value).is_err() {
1187 return false;
1188 }
1189 }
1190 VariableKind::Asset => {
1191 if v.value.is_empty() {
1192 return false;
1193 }
1194 }
1195 VariableKind::Json => {}
1196 },
1197 Variable::External(v) => {
1198 if v.reinitialize && v.update_fn.is_some() {
1199 return false;
1200 }
1201
1202 if let Some(val) = v.value.clone() {
1203 match v.kind {
1204 VariableKind::String => {}
1205 VariableKind::Uint => {
1206 if Uint256::from_str(&val).is_err() {
1207 return false;
1208 }
1209 }
1210 VariableKind::Int => {
1211 if i128::from_str(&val).is_err() {
1212 return false;
1213 }
1214 }
1215 VariableKind::Decimal => {
1216 if Decimal256::from_str(&val).is_err() {
1217 return false;
1218 }
1219 }
1220 VariableKind::Timestamp => {
1221 if i128::from_str(&val).is_err() {
1222 return false;
1223 }
1224 }
1225 VariableKind::Bool => {
1226 if bool::from_str(&val).is_err() {
1227 return false;
1228 }
1229 }
1230 VariableKind::Amount => {
1231 if Uint128::from_str(&val).is_err() {
1232 return false;
1233 }
1234 }
1235 VariableKind::Asset => {
1236 if val.is_empty() {
1237 return false;
1238 }
1239 }
1240 VariableKind::Json => {}
1241 }
1242 }
1243 }
1244 Variable::Query(v) => {
1245 if v.reinitialize && v.update_fn.is_some() {
1246 return false;
1247 }
1248 if let Some(val) = v.value.clone() {
1249 match v.kind {
1250 VariableKind::String => {}
1251 VariableKind::Uint => {
1252 if Uint256::from_str(&val).is_err() {
1253 return false;
1254 }
1255 }
1256 VariableKind::Int => {
1257 if i128::from_str(&val).is_err() {
1258 return false;
1259 }
1260 }
1261 VariableKind::Decimal => {
1262 if Decimal256::from_str(&val).is_err() {
1263 return false;
1264 }
1265 }
1266 VariableKind::Timestamp => {
1267 if i128::from_str(&val).is_err() {
1268 return false;
1269 }
1270 }
1271 VariableKind::Bool => {
1272 if bool::from_str(&val).is_err() {
1273 return false;
1274 }
1275 }
1276 VariableKind::Amount => {
1277 if Uint128::from_str(&val).is_err() {
1278 return false;
1279 }
1280 }
1281 VariableKind::Asset => {
1282 if val.is_empty() {
1283 return false;
1284 }
1285 }
1286 VariableKind::Json => {}
1287 }
1288 }
1289 }
1290 }
1291 }
1292 true
1293}