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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
use crate::{
    values::{Dbi, Hnt, Hst, Usd},
    Error, Result,
};
use chrono::{DateTime, Utc};
use serde::{de, Deserialize, Serialize};
use std::{fmt, str::FromStr};

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Represents a wallet on the blockchain.
pub struct Account {
    /// The wallet address is the base58 check-encoded public key of
    /// the wallet.
    pub address: String,
    /// The latest balance of the wallet known to the API
    #[serde(deserialize_with = "Hnt::deserialize")]
    pub balance: Hnt,
    /// The data credit balance of the wallet known to the API
    pub dc_balance: u64,
    /// The security token balance of the wallet known to the API
    #[serde(deserialize_with = "Hst::deserialize")]
    pub sec_balance: Hst,
    /// The current nonce for the account
    pub nonce: u64,
    /// The speculative nonce for the account
    #[serde(default)]
    pub speculative_nonce: u64,
    /// The speculative security nonce for the account
    #[serde(default)]
    pub speculative_sec_nonce: u64,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Geocode {
    /// The long version of city for the last asserted location
    pub long_city: Option<String>,
    /// The long version of country for the last asserted location
    pub long_country: Option<String>,
    /// The long version of state for the last asserted location
    pub long_state: Option<String>,
    /// The long version of street for the last asserted location
    pub long_street: Option<String>,
    /// The short version of city for the last asserted location
    pub short_city: Option<String>,
    /// The short version of country for the last asserted location
    pub short_country: Option<String>,
    /// The short version of state for the last asserted location
    pub short_state: Option<String>,
    /// The short version of street for the last asserted location
    pub short_street: Option<String>,
}

#[derive(Deserialize)]
pub struct Height {
    /// The current block height of the chain.
    pub height: u64,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Hotspot {
    /// The address of the hotspots. This is the public key in base58
    /// check-encoding of the hotspot.
    pub address: String,
    /// The hotspot owner wallet address
    pub owner: String,
    /// The "animal" name of the hotspot. The name can be `None` for
    /// some API endpoints.
    pub name: Option<String>,
    /// The block height when the hotspot was added to the blockchain
    pub added_height: Option<u64>,
    /// The last asserted latitude of the hotspot
    pub lat: Option<f64>,
    /// The last asserted longitude of the hotspot
    pub lng: Option<f64>,
    /// The h3 index based on the lat/lon of the hotspot is used for
    /// PoC challenges.
    pub location: Option<String>,
    /// The mode in which the hotspots was added to the network.
    pub mode: HotspotStakingMode,
    /// The elevation (in meters) above or belowo sea level
    pub elevation: Option<i32>,
    /// The gain (in dbi) above or belowo sea level
    #[serde(deserialize_with = "Dbi::deserialize_option")]
    pub gain: Option<Dbi>,
    /// The geocode information for the hotspot location
    pub geocode: Geocode,
    /// The current nonce for the hotspot
    pub nonce: u64,
    /// The speculative nonce for the hotspot. This field is only meaningful
    /// when a single hotspot is requested
    #[serde(default)]
    pub speculative_nonce: u64,
}

#[derive(Clone, Serialize, Debug)]
pub enum HotspotStakingMode {
    Full,
    Light,
    DataOnly,
}

impl fmt::Display for HotspotStakingMode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::DataOnly => f.write_str("dataonly"),
            Self::Full => f.write_str("full"),
            Self::Light => f.write_str("light"),
        }
    }
}

impl<'de> Deserialize<'de> for HotspotStakingMode {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        struct HotspotStakingModeVisitor;

        impl<'de> de::Visitor<'de> for HotspotStakingModeVisitor {
            type Value = HotspotStakingMode;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("full, light, dataonly")
            }

            fn visit_str<E>(self, value: &str) -> std::result::Result<HotspotStakingMode, E>
            where
                E: de::Error,
            {
                match HotspotStakingMode::from_str(value) {
                    Ok(v) => Ok(v),
                    Err(_) => Err(de::Error::custom("invalid staking mode")),
                }
            }
        }

        deserializer.deserialize_str(HotspotStakingModeVisitor)
    }
}
impl FromStr for HotspotStakingMode {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        match s.to_lowercase().as_ref() {
            "light" => Ok(Self::Light),
            "full" => Ok(Self::Full),
            "dataonly" => Ok(Self::DataOnly),
            _ => Err(Error::value(s.into())),
        }
    }
}

/// An oracle prediction is inferred from the current oracle price and submitted
/// oracle price reports.
#[derive(Clone, Deserialize, Debug)]
pub struct OraclePrediction {
    /// The oracle price at the indicated block in Usd millis
    #[serde(deserialize_with = "Usd::deserialize")]
    pub price: Usd,
    /// The epoch time when the price is expected to take hold
    pub time: u64,
}

/// An oracle price is inferred from oracle price reports on a regular basis by
/// the blockchain. It determines the conversion rate between Hnt and Data
/// Credits.
#[derive(Clone, Deserialize, Debug)]
pub struct OraclePrice {
    /// The oracle price at the indicated block in Usd millis
    #[serde(deserialize_with = "Usd::deserialize")]
    pub price: Usd,
    /// The block height the oracle price was set at
    pub block: u64,
}

#[derive(Clone, Deserialize, Debug)]
/// Represents an OUI on the blockchain
pub struct Oui {
    /// The oui value.
    pub oui: u64,
    /// The base58 public key of the owner of the oui.
    pub owner: String,
    /// The current nonce for the oui
    pub nonce: u64,
    /// The base58 encoded public keys of the routers for this oui
    pub addresses: Vec<String>,
    /// The subnets for this oui
    pub subnets: Vec<Subnet>,
}

/// Stats for ouis
#[derive(Clone, Deserialize, Debug)]
pub struct OuiStats {
    pub count: u64,
}

#[derive(Clone, Deserialize, Debug)]
pub struct PendingTxnStatus {
    pub hash: String,
}

/// Query params for requests that can take in a time range.
#[derive(Clone, Debug, Serialize)]
pub struct QueryTimeRange {
    /// ISO 8601 timestamp or relative time (-3 hour) minimum time range
    pub min_time: String,
    /// ISO 8601 timestamp or relative time (-3 hour) maximum time range
    pub max_time: String,
}

/// Reward for validator
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Reward {
    /// The owner address is the base58 check-encoded public key of
    /// the owner's wallet address.
    pub account: String,
    /// The reward amount.
    #[serde(deserialize_with = "Hnt::deserialize")]
    pub amount: Hnt,
    /// The block the reward was earned in.
    pub block: i64,
    /// The validator address is the base58 check-encoded public key of
    /// the validator.
    pub gateway: String,
    /// The transaction hash of the reward.
    pub hash: String,
    /// The timestamp of the rewards.
    pub timestamp: DateTime<Utc>,
}

/// Stats for a specific validator stake status
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct StakeStats {
    /// The amount of HNT committed in the staked status
    pub amount: Hnt,
    /// The number of validators in the staked status
    pub count: u64,
}

#[derive(Clone, Deserialize, Debug)]
/// An OUI owns a list of subnets, which are used to check if packets from a
/// device with a given DevAddr need to be sent to the routers in the OUI
pub struct Subnet {
    base: u32,
    mask: u32,
}

impl fmt::Display for Subnet {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!("{}/{}", self.base, self.mask))
    }
}

#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
/// The Penalty types reported for a validator.
pub enum PenaltyType {
    Performance,
    Tenure,
    Dkg,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Represents a penalty for a validator.
pub struct Penalty {
    /// The type of penalty
    #[serde(rename = "type")]
    pub kind: PenaltyType,
    /// The block the penalty occured in.
    pub height: u64,
    /// The amount of penalty.
    pub amount: f64,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Represents a validator on the blockchain.
pub struct Validator {
    /// The validator address is the base58 check-encoded public key of
    /// the validator.
    pub address: String,
    /// The validator pwner is the base58 check-encoded public key of
    /// the owner of the validator.
    pub owner: String,
    /// The staked amount for the validator
    #[serde(deserialize_with = "Hnt::deserialize")]
    pub stake: Hnt,
    /// The last heartbeat transaction of the validator
    pub last_heartbeat: u64,
    /// The last heartbeat version of the validator heartbeat
    pub version_heartbeat: u64,
    /// The current status of the validator (staked, cooldown, unstaked)
    pub stake_status: String,
    /// The total penalty of the validator
    pub penalty: f64,
    /// A list of penalties this validator has received
    pub penalties: Vec<Penalty>,
    /// The block this validator was added to chain
    pub block_added: u64,
    /// The current block this validator is synced to
    pub block: u64,
}

/// Stats for validators
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct ValidatorStats {
    /// The number of active validators. An active validator is one that emits
    /// heartbeat transactions on a regular basis. `None` indicates the active
    /// number is unknown at this time.
    pub active: Option<u64>,
    pub staked: StakeStats,
    pub unstaked: StakeStats,
    pub cooldown: StakeStats,
}