1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! Common structures between the environment and the SDK.
//! This crate omits the structures that are shared between
//! Zephyr and Mercury due to the latter's closed-source nature.

pub mod http;
pub mod log;
pub mod wrapping;

pub fn to_fixed<T, const N: usize>(v: Vec<T>) -> [T; N] {
    v.try_into()
        .unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
}

#[repr(u32)]
pub enum ZephyrStatus {
    Unknown = 0,
    Success = 1,
    DbWriteError = 2,
    DbReadError = 3,
    NoValOnStack = 4,
    HostConfiguration = 5,
}

use http::AgnosticRequest;
use log::ZephyrLog;
use serde::{Deserialize, Serialize};
use stellar_xdr::next::{LedgerEntry, ScAddress, ScVal};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum DatabaseError {
    #[error("Invalid permissions. Tried reading when in write-only")]
    ReadOnWriteOnly,

    #[error("Invalid permissions. Tried writing when in read-only")]
    WriteOnReadOnly,

    #[error("Zephyr query malformed.")]
    ZephyrQueryMalformed,

    #[error("Zephyr query error.")]
    ZephyrQueryError,

    #[error("Unable to write to DB.")]
    WriteError,

    #[error("Unable to parse operator.")]
    OperatorError,
}

impl From<anyhow::Error> for ZephyrStatus {
    fn from(value: anyhow::Error) -> Self {
        match value.downcast_ref() {
            Some(DatabaseError::WriteError) => ZephyrStatus::DbWriteError,
            Some(DatabaseError::ZephyrQueryError) => ZephyrStatus::DbReadError,
            Some(DatabaseError::ZephyrQueryMalformed) => ZephyrStatus::DbReadError,
            Some(DatabaseError::ReadOnWriteOnly) => ZephyrStatus::HostConfiguration,
            Some(DatabaseError::WriteOnReadOnly) => ZephyrStatus::HostConfiguration,
            Some(DatabaseError::OperatorError) => ZephyrStatus::DbWriteError, // todo: specific error
            None => ZephyrStatus::Unknown,
        }
    }
}

impl From<u32> for ZephyrStatus {
    fn from(value: u32) -> Self {
        match value {
            0 => Self::Unknown,
            1 => Self::Success,
            2 => Self::DbWriteError,
            3 => Self::DbReadError,
            4 => Self::NoValOnStack,
            5 => Self::HostConfiguration,
            _ => panic!("Unrecoverable status"),
        }
    }
}

#[derive(Deserialize, Serialize, Clone)]
pub enum ZephyrVal {
    I128(i128),
    I64(i64),
    U64(u64),
    F64(f64),
    U32(u32),
    I32(i32),
    F32(f32),
    String(String),
    Bytes(Vec<u8>),
}

#[derive(Debug)]
pub enum ZephyrValError {
    ConversionError,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ContractDataEntry {
    pub contract_id: ScAddress,
    pub key: ScVal,
    pub entry: LedgerEntry,
    pub durability: i32,
    pub last_modified: i32,
}


#[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct Account {
    pub account_id: String,
    pub native_balance: f64,
    pub buying_liabilities: f64,
    pub selling_liabilities: f64,
    pub seq_num: f64,
    pub num_subentries: i32,
    pub num_sponsored: i32,
    pub num_sponsoring: i32,
}

macro_rules! impl_inner_from_serialize_only {
    ($variant:ident, $inner:ty) => {
        impl From<$inner> for ZephyrVal {
            fn from(value: $inner) -> Self {
                ZephyrVal::$variant(value)
            }
        }
    };
}

macro_rules! impl_inner_from_deserialize_generic {
    ($variant:ident, $inner:ty) => {
        impl From<ZephyrVal> for $inner {
            fn from(value: ZephyrVal) -> Self {
                match value {
                    ZephyrVal::$variant(inner_val) => inner_val,
                    _ => panic!("Attempted to convert ZephyrVal variant to different inner type"),
                }
            }
        }
    };
}

macro_rules! impl_inner_from_deserialize_numeric {
    ($inner:ty) => {
        impl From<ZephyrVal> for $inner {
            fn from(value: ZephyrVal) -> Self {
                match value {
                    //ZephyrVal::F32(num) => num as $inner,
                    //ZephyrVal::F64(num) => num as $inner,
                    ZephyrVal::I128(num) => num as $inner,
                    ZephyrVal::I32(num) => num as $inner,
                    ZephyrVal::I64(num) => num as $inner,
                    ZephyrVal::U32(num) => num as $inner,
                    ZephyrVal::U64(num) => num as $inner,
                    _ => panic!("Attempted to convert ZephyrVal variant to different inner type"),
                }
            }
        }
    };
}

// Ser
impl_inner_from_serialize_only!(I128, i128);
impl_inner_from_serialize_only!(I64, i64);
impl_inner_from_serialize_only!(U64, u64);
impl_inner_from_serialize_only!(F64, f64);
impl_inner_from_serialize_only!(U32, u32);
impl_inner_from_serialize_only!(I32, i32);
impl_inner_from_serialize_only!(F32, f32);
impl_inner_from_serialize_only!(String, String);
impl_inner_from_serialize_only!(Bytes, Vec<u8>);

// Deser
impl_inner_from_deserialize_numeric!(i128);
impl_inner_from_deserialize_numeric!(i64);
impl_inner_from_deserialize_numeric!(u64);
impl_inner_from_deserialize_numeric!(u32);
impl_inner_from_deserialize_numeric!(i32);
impl_inner_from_deserialize_generic!(String, String);
impl_inner_from_deserialize_generic!(Bytes, Vec<u8>);
impl_inner_from_deserialize_generic!(F64, f64);
impl_inner_from_deserialize_generic!(F32, f32);


#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum RelayedMessageRequest {
    Http(AgnosticRequest),
    Log(ZephyrLog),
}