warp_resolver/util/
variable.rs

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                                // \"$warp.variable\" => \"VALUE"\
72                                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}