warp_resolver/util/
condition.rs

1use crate::util::path::resolve_path;
2use crate::util::variable::get_var;
3use crate::ContractError;
4use cosmwasm_std::{
5    to_vec, ContractResult, Decimal256, Deps, Env, StdError, SystemResult, Uint256,
6};
7use cw_storage_plus::KeyDeserialize;
8use json_codec_wasm::ast::Ref;
9use json_codec_wasm::Decoder;
10use warp_resolver_pkg::condition::{
11    BlockExpr, Condition, DecimalFnOp, Expr, GenExpr, IntFnOp, NumEnvValue, NumExprOp,
12    NumExprValue, NumFnValue, NumOp, NumValue, StringOp, TimeExpr, TimeOp, Value,
13};
14use warp_resolver_pkg::variable::{QueryExpr, Variable};
15use std::str::FromStr;
16
17pub fn resolve_cond(
18    deps: Deps,
19    env: Env,
20    cond: Condition,
21    vars: &Vec<Variable>,
22) -> Result<bool, ContractError> {
23    match cond {
24        Condition::And(conds) => {
25            for cond in conds {
26                if !resolve_cond(deps, env.clone(), *cond, vars)? {
27                    return Ok(false);
28                }
29            }
30            Ok(true)
31        }
32        Condition::Or(conds) => {
33            for cond in conds {
34                if resolve_cond(deps, env.clone(), *cond, vars)? {
35                    return Ok(true);
36                }
37            }
38            Ok(false)
39        }
40        Condition::Not(cond) => Ok(!resolve_cond(deps, env, *cond, vars)?),
41        Condition::Expr(expr) => Ok(resolve_expr(deps, env, *expr, vars)?),
42    }
43}
44
45pub fn resolve_expr(
46    deps: Deps,
47    env: Env,
48    expr: Expr,
49    vars: &Vec<Variable>,
50) -> Result<bool, ContractError> {
51    match expr {
52        Expr::String(expr) => resolve_string_expr(deps, env, expr, vars),
53        Expr::Uint(expr) => resolve_uint_expr(deps, env, expr, vars),
54        Expr::Int(expr) => resolve_int_expr(deps, env, expr, vars),
55        Expr::Decimal(expr) => resolve_decimal_expr(deps, env, expr, vars),
56        Expr::Timestamp(expr) => resolve_timestamp_expr(deps, env, expr),
57        Expr::BlockHeight(expr) => resolve_block_expr(deps, env, expr),
58        Expr::Bool(expr) => resolve_ref_bool(deps, env, expr, vars),
59    }
60}
61
62pub fn resolve_int_expr(
63    deps: Deps,
64    env: Env,
65    expr: GenExpr<NumValue<i128, NumExprOp, IntFnOp>, NumOp>,
66    vars: &Vec<Variable>,
67) -> Result<bool, ContractError> {
68    let left = resolve_num_value_int(deps, env.clone(), expr.left, vars)?;
69    let right = resolve_num_value_int(deps, env.clone(), expr.right, vars)?;
70
71    Ok(resolve_int_op(deps, env, left, right, expr.op))
72}
73
74pub fn resolve_num_value_int(
75    deps: Deps,
76    env: Env,
77    value: NumValue<i128, NumExprOp, IntFnOp>,
78    vars: &Vec<Variable>,
79) -> Result<i128, ContractError> {
80    match value {
81        NumValue::Simple(value) => Ok(value),
82        NumValue::Expr(expr) => resolve_num_expr_int(deps, env, expr, vars),
83        NumValue::Ref(expr) => resolve_ref_int(deps, env, expr, vars),
84        NumValue::Fn(expr) => resolve_num_fn_int(deps, env, expr, vars),
85        NumValue::Env(_expr) => Err(ContractError::ConditionError {
86            msg: "Int resolve Env.".to_string(),
87        }),
88    }
89}
90
91fn resolve_ref_int(
92    _deps: Deps,
93    _env: Env,
94    r: String,
95    vars: &Vec<Variable>,
96) -> Result<i128, ContractError> {
97    let var = get_var(r, vars)?;
98    let res = match var {
99        Variable::Static(s) => {
100            let val = s.clone().value;
101            str::parse::<i128>(&val)?
102        }
103        Variable::Query(q) => {
104            let val = q.clone().value.ok_or(ContractError::ConditionError {
105                msg: format!("Int Query value not found: {}", q.name),
106            })?;
107            str::parse::<i128>(&val)?
108        }
109        Variable::External(e) => {
110            let val = e.clone().value.ok_or(ContractError::ConditionError {
111                msg: format!("Int External value not found: {}", e.name),
112            })?;
113            str::parse::<i128>(&val)?
114        }
115    };
116
117    Ok(res)
118}
119
120fn resolve_num_fn_int(
121    deps: Deps,
122    env: Env,
123    expr: NumFnValue<i128, NumExprOp, IntFnOp>,
124    vars: &Vec<Variable>,
125) -> Result<i128, ContractError> {
126    let right = resolve_num_value_int(deps, env, *expr.right, vars)?;
127
128    match expr.op {
129        IntFnOp::Abs => Ok(right.abs()),
130        IntFnOp::Neg => {
131            Ok(right
132                .checked_mul(i128::from(-1i64))
133                .ok_or(ContractError::ConditionError {
134                    msg: "Int negation error.".to_string(),
135                })?)
136        }
137    }
138}
139
140pub fn resolve_num_expr_int(
141    deps: Deps,
142    env: Env,
143    expr: NumExprValue<i128, NumExprOp, IntFnOp>,
144    vars: &Vec<Variable>,
145) -> Result<i128, ContractError> {
146    let left = resolve_num_value_int(deps, env.clone(), *expr.left, vars)?;
147    let right = resolve_num_value_int(deps, env, *expr.right, vars)?;
148
149    match expr.op {
150        NumExprOp::Sub => Ok(left
151            .checked_sub(right)
152            .ok_or(ContractError::ConditionError {
153                msg: "Int checked sub error.".to_string(),
154            })?),
155        NumExprOp::Add => Ok(left
156            .checked_add(right)
157            .ok_or(ContractError::ConditionError {
158                msg: "Int checked add error.".to_string(),
159            })?),
160        NumExprOp::Div => Ok(left
161            .checked_div(right)
162            .ok_or(ContractError::ConditionError {
163                msg: "Int checked div error.".to_string(),
164            })?),
165        NumExprOp::Mul => Ok(left
166            .checked_mul(right)
167            .ok_or(ContractError::ConditionError {
168                msg: "Int checked mul error.".to_string(),
169            })?),
170        NumExprOp::Mod => Ok(left
171            .checked_rem(right)
172            .ok_or(ContractError::ConditionError {
173                msg: "Int checked rem error.".to_string(),
174            })?),
175    }
176}
177
178pub fn resolve_uint_expr(
179    deps: Deps,
180    env: Env,
181    expr: GenExpr<NumValue<Uint256, NumExprOp, IntFnOp>, NumOp>,
182    vars: &Vec<Variable>,
183) -> Result<bool, ContractError> {
184    let left = resolve_num_value_uint(deps, env.clone(), expr.left, vars)?;
185    let right = resolve_num_value_uint(deps, env.clone(), expr.right, vars)?;
186
187    Ok(resolve_uint_op(deps, env, left, right, expr.op))
188}
189
190pub fn resolve_num_value_uint(
191    deps: Deps,
192    env: Env,
193    value: NumValue<Uint256, NumExprOp, IntFnOp>,
194    vars: &Vec<Variable>,
195) -> Result<Uint256, ContractError> {
196    match value {
197        NumValue::Simple(value) => Ok(value),
198        NumValue::Expr(expr) => resolve_num_expr_uint(deps, env, expr, vars),
199        NumValue::Ref(expr) => resolve_ref_uint(deps, env, expr, vars),
200        NumValue::Fn(_) => Err(ContractError::ConditionError {
201            msg: "Uint resolve Fn.".to_string(),
202        }),
203        NumValue::Env(expr) => resolve_num_env_uint(deps, env, expr, vars),
204    }
205}
206
207fn resolve_ref_uint(
208    _deps: Deps,
209    _env: Env,
210    r: String,
211    vars: &Vec<Variable>,
212) -> Result<Uint256, ContractError> {
213    let var = get_var(r, vars)?;
214    let res = match var {
215        Variable::Static(s) => {
216            let val = s.clone().value;
217            Uint256::from_str(&val)?
218        }
219        Variable::Query(q) => {
220            let val = q.clone().value.ok_or(ContractError::ConditionError {
221                msg: format!("Uint Query value not found: {}", q.name),
222            })?;
223            Uint256::from_str(&val)?
224        }
225        Variable::External(e) => {
226            let val = e.clone().value.ok_or(ContractError::ConditionError {
227                msg: format!("Uint External value not found: {}", e.name),
228            })?;
229            Uint256::from_str(&val)?
230        }
231    };
232
233    Ok(res)
234}
235
236pub fn resolve_num_expr_uint(
237    deps: Deps,
238    env: Env,
239    expr: NumExprValue<Uint256, NumExprOp, IntFnOp>,
240    vars: &Vec<Variable>,
241) -> Result<Uint256, ContractError> {
242    let left = resolve_num_value_uint(deps, env.clone(), *expr.left, vars)?;
243    let right = resolve_num_value_uint(deps, env, *expr.right, vars)?;
244
245    match expr.op {
246        NumExprOp::Sub => {
247            Ok(left
248                .checked_sub(right)
249                .map_err(|_| ContractError::ConditionError {
250                    msg: "Uint checked sub error.".to_string(),
251                })?)
252        }
253        NumExprOp::Add => {
254            Ok(left
255                .checked_add(right)
256                .map_err(|_| ContractError::ConditionError {
257                    msg: "Uint checked add error.".to_string(),
258                })?)
259        }
260        NumExprOp::Div => {
261            Ok(left
262                .checked_div(right)
263                .map_err(|_| ContractError::ConditionError {
264                    msg: "Uint checked div error.".to_string(),
265                })?)
266        }
267        NumExprOp::Mul => {
268            Ok(left
269                .checked_mul(right)
270                .map_err(|_| ContractError::ConditionError {
271                    msg: "Uint checked mul error.".to_string(),
272                })?)
273        }
274        NumExprOp::Mod => {
275            Ok(left
276                .checked_rem(right)
277                .map_err(|_| ContractError::ConditionError {
278                    msg: "Uint checked rem error.".to_string(),
279                })?)
280        }
281    }
282}
283
284pub fn resolve_num_env_uint(
285    _deps: Deps,
286    env: Env,
287    expr: NumEnvValue,
288    _vars: &[Variable],
289) -> Result<Uint256, ContractError> {
290    match expr {
291        NumEnvValue::Time => Ok(env.block.time.seconds().into()),
292        NumEnvValue::BlockHeight => Ok(env.block.height.into()),
293    }
294}
295
296pub fn resolve_decimal_expr(
297    deps: Deps,
298    env: Env,
299    expr: GenExpr<NumValue<Decimal256, NumExprOp, DecimalFnOp>, NumOp>,
300    vars: &Vec<Variable>,
301) -> Result<bool, ContractError> {
302    let left = resolve_num_value_decimal(deps, env.clone(), expr.left, vars)?;
303    let right = resolve_num_value_decimal(deps, env.clone(), expr.right, vars)?;
304
305    Ok(resolve_decimal_op(deps, env, left, right, expr.op))
306}
307
308pub fn resolve_num_value_decimal(
309    deps: Deps,
310    env: Env,
311    value: NumValue<Decimal256, NumExprOp, DecimalFnOp>,
312    vars: &Vec<Variable>,
313) -> Result<Decimal256, ContractError> {
314    match value {
315        NumValue::Simple(value) => Ok(value),
316        NumValue::Expr(expr) => resolve_num_expr_decimal(deps, env, expr, vars),
317        NumValue::Ref(expr) => resolve_ref_decimal(deps, env, expr, vars),
318        NumValue::Fn(expr) => resolve_num_fn_decimal(deps, env, expr, vars),
319        NumValue::Env(_expr) => Err(ContractError::ConditionError {
320            msg: "Decimal resolve Env.".to_string(),
321        }),
322    }
323}
324
325fn resolve_ref_decimal(
326    _deps: Deps,
327    _env: Env,
328    r: String,
329    vars: &Vec<Variable>,
330) -> Result<Decimal256, ContractError> {
331    let var = get_var(r, vars)?;
332    let res = match var {
333        Variable::Static(s) => {
334            let val = s.clone().value;
335            Decimal256::from_str(&val)?
336        }
337        Variable::Query(q) => {
338            let val = q.clone().value.ok_or(ContractError::ConditionError {
339                msg: format!("Decimal Query value not found: {}", q.name),
340            })?;
341            Decimal256::from_str(&val)?
342        }
343        Variable::External(e) => {
344            let val = e.clone().value.ok_or(ContractError::ConditionError {
345                msg: format!("Decimal External value not found: {}", e.name),
346            })?;
347            Decimal256::from_str(&val)?
348        }
349    };
350
351    Ok(res)
352}
353
354fn resolve_num_fn_decimal(
355    deps: Deps,
356    env: Env,
357    expr: NumFnValue<Decimal256, NumExprOp, DecimalFnOp>,
358    vars: &Vec<Variable>,
359) -> Result<Decimal256, ContractError> {
360    let right = resolve_num_value_decimal(deps, env, *expr.right, vars)?;
361
362    match expr.op {
363        DecimalFnOp::Abs => Ok(right.abs_diff(Decimal256::zero())),
364        DecimalFnOp::Neg => {
365            Ok(right.checked_mul(Decimal256::zero().checked_sub(Decimal256::one())?)?)
366        }
367        DecimalFnOp::Floor => Ok(right.floor()),
368        DecimalFnOp::Sqrt => Ok(right.sqrt()),
369        DecimalFnOp::Ceil => Ok(right.ceil()),
370    }
371}
372
373pub fn resolve_num_expr_decimal(
374    deps: Deps,
375    env: Env,
376    expr: NumExprValue<Decimal256, NumExprOp, DecimalFnOp>,
377    vars: &Vec<Variable>,
378) -> Result<Decimal256, ContractError> {
379    let left = resolve_num_value_decimal(deps, env.clone(), *expr.left, vars)?;
380    let right = resolve_num_value_decimal(deps, env, *expr.right, vars)?;
381
382    match expr.op {
383        NumExprOp::Sub => {
384            Ok(left
385                .checked_sub(right)
386                .map_err(|_| ContractError::ConditionError {
387                    msg: "Decimal checked sub error.".to_string(),
388                })?)
389        }
390        NumExprOp::Add => {
391            Ok(left
392                .checked_add(right)
393                .map_err(|_| ContractError::ConditionError {
394                    msg: "Decimal checked sub error.".to_string(),
395                })?)
396        }
397        NumExprOp::Div => {
398            Ok(left
399                .checked_div(right)
400                .map_err(|_| ContractError::ConditionError {
401                    msg: "Decimal checked sub error.".to_string(),
402                })?)
403        }
404        NumExprOp::Mul => {
405            Ok(left
406                .checked_mul(right)
407                .map_err(|_| ContractError::ConditionError {
408                    msg: "Decimal checked sub error.".to_string(),
409                })?)
410        }
411        NumExprOp::Mod => {
412            Ok(left
413                .checked_rem(right)
414                .map_err(|_| ContractError::ConditionError {
415                    msg: "Decimal checked sub error.".to_string(),
416                })?)
417        }
418    }
419}
420
421pub fn resolve_timestamp_expr(
422    _deps: Deps,
423    env: Env,
424    expr: TimeExpr,
425) -> Result<bool, ContractError> {
426    let res = match expr.op {
427        TimeOp::Lt => env.block.time.seconds().lt(&expr.comparator.u64()),
428        TimeOp::Gt => env.block.time.seconds().gt(&expr.comparator.u64()),
429    };
430
431    Ok(res)
432}
433
434pub fn resolve_block_expr(_deps: Deps, env: Env, expr: BlockExpr) -> Result<bool, ContractError> {
435    let res = match expr.op {
436        NumOp::Eq => env.block.height.eq(&expr.comparator.u64()),
437        NumOp::Neq => env.block.height.ne(&expr.comparator.u64()),
438        NumOp::Lt => env.block.height.lt(&expr.comparator.u64()),
439        NumOp::Gt => env.block.height.gt(&expr.comparator.u64()),
440        NumOp::Gte => env.block.height.ge(&expr.comparator.u64()),
441        NumOp::Lte => env.block.height.le(&expr.comparator.u64()),
442    };
443
444    Ok(res)
445}
446
447pub fn resolve_uint_op(_deps: Deps, _env: Env, left: Uint256, right: Uint256, op: NumOp) -> bool {
448    match op {
449        NumOp::Eq => left.eq(&right),
450        NumOp::Neq => left.ne(&right),
451        NumOp::Lt => left.lt(&right),
452        NumOp::Gt => left.gt(&right),
453        NumOp::Gte => left.ge(&right),
454        NumOp::Lte => left.le(&right),
455    }
456}
457
458pub fn resolve_int_op(_deps: Deps, _env: Env, left: i128, right: i128, op: NumOp) -> bool {
459    match op {
460        NumOp::Eq => left.eq(&right),
461        NumOp::Neq => left.ne(&right),
462        NumOp::Lt => left.lt(&right),
463        NumOp::Gt => left.gt(&right),
464        NumOp::Gte => left.ge(&right),
465        NumOp::Lte => left.le(&right),
466    }
467}
468
469pub fn resolve_decimal_op(
470    _deps: Deps,
471    _env: Env,
472    left: Decimal256,
473    right: Decimal256,
474    op: NumOp,
475) -> bool {
476    match op {
477        NumOp::Eq => left.eq(&right),
478        NumOp::Neq => left.ne(&right),
479        NumOp::Lt => left.lt(&right),
480        NumOp::Gt => left.gt(&right),
481        NumOp::Gte => left.ge(&right),
482        NumOp::Lte => left.le(&right),
483    }
484}
485
486pub fn resolve_string_expr(
487    deps: Deps,
488    env: Env,
489    expr: GenExpr<Value<String>, StringOp>,
490    vars: &Vec<Variable>,
491) -> Result<bool, ContractError> {
492    match (expr.left, expr.right) {
493        (Value::Simple(left), Value::Simple(right)) => {
494            Ok(resolve_str_op(deps, env, left, right, expr.op))
495        }
496        (Value::Simple(left), Value::Ref(right)) => Ok(resolve_str_op(
497            deps,
498            env.clone(),
499            left,
500            resolve_ref_string(deps, env, right, vars)?,
501            expr.op,
502        )),
503        (Value::Ref(left), Value::Simple(right)) => Ok(resolve_str_op(
504            deps,
505            env.clone(),
506            resolve_ref_string(deps, env, left, vars)?,
507            right,
508            expr.op,
509        )),
510        (Value::Ref(left), Value::Ref(right)) => Ok(resolve_str_op(
511            deps,
512            env.clone(),
513            resolve_ref_string(deps, env.clone(), left, vars)?,
514            resolve_ref_string(deps, env, right, vars)?,
515            expr.op,
516        )),
517    }
518}
519
520fn resolve_ref_string(
521    _deps: Deps,
522    _env: Env,
523    r: String,
524    vars: &Vec<Variable>,
525) -> Result<String, ContractError> {
526    let var = get_var(r, vars)?;
527    let res = match var {
528        Variable::Static(s) => s.value.clone(),
529        Variable::Query(q) => q.value.clone().ok_or(ContractError::ConditionError {
530            msg: format!("String Query value not found: {}", q.name),
531        })?,
532        Variable::External(e) => e.value.clone().ok_or(ContractError::ConditionError {
533            msg: format!("String External value not found: {}", e.name),
534        })?,
535    };
536
537    Ok(res)
538}
539
540pub fn resolve_str_op(_deps: Deps, _env: Env, left: String, right: String, op: StringOp) -> bool {
541    match op {
542        StringOp::StartsWith => left.starts_with(&right),
543        StringOp::EndsWith => left.ends_with(&right),
544        StringOp::Contains => left.contains(&right),
545        StringOp::Eq => left.eq(&right),
546        StringOp::Neq => left.ne(&right),
547    }
548}
549
550pub fn resolve_query_expr(deps: Deps, _env: Env, expr: QueryExpr) -> Result<String, ContractError> {
551    let raw = to_vec(&expr.query).map_err(|serialize_err| {
552        StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err))
553    })?;
554
555    let query_result_binary = match deps.querier.raw_query(&raw) {
556        SystemResult::Err(system_err) => Err(StdError::generic_err(format!(
557            "Querier system error: {}",
558            system_err
559        ))),
560        SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(format!(
561            "Querier contract error: {}",
562            contract_err
563        ))),
564        SystemResult::Ok(ContractResult::Ok(value)) => Ok(value),
565    }?;
566
567    let query_result_str = String::from_vec(base64::decode(query_result_binary.to_string())?)?;
568
569    Ok(query_result_str)
570}
571
572pub fn resolve_query_expr_bool(
573    deps: Deps,
574    env: Env,
575    expr: QueryExpr,
576) -> Result<bool, ContractError> {
577    let query_result_str = resolve_query_expr(deps, env, expr.clone())?;
578    let value = Decoder::default(query_result_str.chars()).decode()?;
579    let r = Ref::new(&value);
580    let resolved = resolve_path(r, expr.selector)?;
581
582    resolved.bool().ok_or(ContractError::DecodeError {})
583}
584
585pub fn resolve_ref_bool(
586    _deps: Deps,
587    _env: Env,
588    r: String,
589    vars: &Vec<Variable>,
590) -> Result<bool, ContractError> {
591    let var = get_var(r, vars)?;
592    let res = match var {
593        Variable::Static(s) => {
594            let val = s.clone().value;
595            str::parse::<bool>(&val)?
596        }
597        Variable::Query(q) => {
598            let val = q.clone().value.ok_or(ContractError::ConditionError {
599                msg: format!("Bool Query value not found: {}", q.name),
600            })?;
601            str::parse::<bool>(&val)?
602        }
603        Variable::External(e) => {
604            let val = e.clone().value.ok_or(ContractError::ConditionError {
605                msg: format!("Bool External value not found: {}", e.name),
606            })?;
607            str::parse::<bool>(&val)?
608        }
609    };
610    Ok(res)
611}
612
613pub fn resolve_query_expr_uint(
614    deps: Deps,
615    env: Env,
616    expr: QueryExpr,
617) -> Result<Uint256, ContractError> {
618    let query_result_str = resolve_query_expr(deps, env, expr.clone())?;
619    let value = Decoder::default(query_result_str.chars()).decode()?;
620    let r = Ref::new(&value);
621    let resolved = resolve_path(r, expr.selector)?;
622
623    let str_result = Uint256::from_str(resolved.string().ok_or(ContractError::DecodeError {})?);
624
625    let val = match str_result {
626        Ok(result) => result,
627        Err(_) => Uint256::from(resolved.u128().ok_or(ContractError::DecodeError {})?),
628    };
629
630    Ok(val)
631}
632
633pub fn resolve_query_expr_int(
634    deps: Deps,
635    env: Env,
636    expr: QueryExpr,
637) -> Result<i128, ContractError> {
638    let query_result_str = resolve_query_expr(deps, env, expr.clone())?;
639    let value = Decoder::default(query_result_str.chars()).decode()?;
640    let r = Ref::new(&value);
641    let resolved = resolve_path(r, expr.selector)?;
642
643    resolved.i128().ok_or(ContractError::DecodeError {})
644}
645
646pub fn resolve_query_expr_decimal(
647    deps: Deps,
648    env: Env,
649    expr: QueryExpr,
650) -> Result<Decimal256, ContractError> {
651    let query_result_str = resolve_query_expr(deps, env, expr.clone())?;
652    let value = Decoder::default(query_result_str.chars()).decode()?;
653    let r = Ref::new(&value);
654    let resolved = resolve_path(r, expr.selector)?;
655
656    Ok(Decimal256::from_str(
657        resolved.string().ok_or(ContractError::DecodeError {})?,
658    )?)
659}
660
661pub fn resolve_query_expr_string(
662    deps: Deps,
663    env: Env,
664    expr: QueryExpr,
665) -> Result<String, ContractError> {
666    let query_result_str = resolve_query_expr(deps, env, expr.clone())?;
667    let value = Decoder::default(query_result_str.chars()).decode()?;
668    let r = Ref::new(&value);
669    let resolved = resolve_path(r, expr.selector)?;
670
671    Ok(resolved
672        .string()
673        .ok_or(ContractError::DecodeError {})?
674        .to_string())
675}