diff --git a/agorata_contracts/src/lib.rs b/agorata_contracts/src/lib.rs index 061bd89..b050ce8 100644 --- a/agorata_contracts/src/lib.rs +++ b/agorata_contracts/src/lib.rs @@ -1,6 +1,9 @@ extern crate serde; +/// Message and Address types pub mod message; +/// Templating variables. +pub mod templates; #[cfg(test)] mod tests { diff --git a/agorata_contracts/src/message.rs b/agorata_contracts/src/message.rs index 8be9642..a8d571d 100644 --- a/agorata_contracts/src/message.rs +++ b/agorata_contracts/src/message.rs @@ -46,5 +46,4 @@ pub struct Message { pub amount: i64, /// Other currencies. pub amounts: Vec<(String, i64)>, - } diff --git a/agorata_contracts/src/templates.rs b/agorata_contracts/src/templates.rs new file mode 100644 index 0000000..ff7130a --- /dev/null +++ b/agorata_contracts/src/templates.rs @@ -0,0 +1,97 @@ +use serde::{Deserialize, Serialize}; +use crate::message::Address; + +/// Values used for variables in templates. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Value { + Int(i64), + Bool(bool), + Address(Address), + Token(Address), + Data(Vec), + String(String), +} + +/// Types for variable values. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] +pub enum Type { + Int, + Bool, + Address, + Token, + Data, + String, +} + +impl Value { + /// Returns the type of the value. + pub fn var_type(&self) -> Type { + match self { + Value::Int(_) => Type::Int, + Value::Bool(_) => Type::Bool, + Value::Address(_) => Type::Address, + Value::Token(_) => Type::Token, + Value::Data(_) => Type::Data, + Value::String(_) => Type::String, + } + } +} + +/// Matchers of values +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Matcher { + Any, + Fixed(Value), + NotEqual(Value), + Whitelist(Vec), + Blacklist(Vec), + IntRange(i64, i64), + Regexp(String), +} + +impl Matcher { + /// Check if this is a valid matcher for a given type. + pub fn check_correctness_for_type(&self, type_: Type) -> bool { + match self { + Matcher::Any => true, + Matcher::Fixed(v) => v.var_type() == type_, + Matcher::NotEqual(v) => v.var_type() == type_, + Matcher::Whitelist(v) | Matcher::Blacklist(v) => { + if v.is_empty() { + return false; + } + // Check that all values are of the same type and that there are no duplicates. + if v.iter().any(|v| v.var_type() != type_) { + return false; + } + let mut v_clone = v.clone(); + v_clone.dedup(); + v_clone.len() == v.len() + }, + Matcher::IntRange(i1, i2) => i1 <= i2 && type_ == Type::Int, + Matcher::Regexp(_) => type_ == Type::String, + } + } + + /// Match a value + pub fn match_value(&self, value: &Value) -> bool { + if !self.check_correctness_for_type(value.var_type()) { + return false; + } + match self { + Matcher::Any => true, + Matcher::Fixed(v) => v == value, + Matcher::NotEqual(v) => v != value, + Matcher::Whitelist(v) => v.contains(value), + Matcher::Blacklist(v) => !v.contains(value), + Matcher::IntRange(i1, i2) => match value { + Value::Int(i) => i >= i1 && i <= i2, + _ => false, + }, + Matcher::Regexp(_regexp) => match value { + Value::String(_s) => todo!(), + _ => false, + }, + } + } +}