Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca98a17db3 | |||
| 11f56cd0d7 | |||
| 185884f546 | |||
| ae0883241e | |||
| 11baa99c4b | |||
| 8bc23434ab | |||
| 8f6daf1e03 | |||
| 7f63377d22 | |||
| 46cb3eca38 | |||
| 7b22872c6b | |||
| 3342cb13c7 | |||
| 3cd5fc3b22 |
Generated
+9
-6
@@ -3972,10 +3972,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "okapi"
|
name = "okapi"
|
||||||
version = "0.6.0-alpha-1"
|
version = "0.7.0-rc.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb085e00daf8d75b9dbf0ffdb4738e69503e28898d9641fa8bdc6ad536c7bcf4"
|
checksum = "ce66b6366e049880a35c378123fddb630b1a1a3c37fa1ca70caaf4a09f6e2893"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"log",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -5212,10 +5213,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rocket_okapi"
|
name = "rocket_okapi"
|
||||||
version = "0.7.0-alpha-1"
|
version = "0.8.0-rc.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b2f4f48fb070f9f6c56d5663df5fa8a514406207744f4abd84661bfb24efd7d"
|
checksum = "0025aa04994af8cd8e1fcdd5a73579a395c941ae090ecb0a39b41cca7e237a20"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"log",
|
||||||
"okapi",
|
"okapi",
|
||||||
"rocket",
|
"rocket",
|
||||||
"rocket_okapi_codegen",
|
"rocket_okapi_codegen",
|
||||||
@@ -5226,9 +5229,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rocket_okapi_codegen"
|
name = "rocket_okapi_codegen"
|
||||||
version = "0.7.0-alpha-1"
|
version = "0.8.0-rc.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88ccf1550e1c806461a6b08e2ab64eb10701d41bf50bde59ab9aa3a57ab14d41"
|
checksum = "dc114779fc27afb78179233e966f469e47fd7a98dc15181cff2574cdddb65612"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling 0.13.0",
|
"darling 0.13.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|||||||
@@ -207,9 +207,9 @@ mod tests {
|
|||||||
fn generating_account_addresses() {
|
fn generating_account_addresses() {
|
||||||
// test vectors produced from our js wallet
|
// test vectors produced from our js wallet
|
||||||
let mnemonic_address = vec![
|
let mnemonic_address = vec![
|
||||||
("crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove", "punk1jw6mp7d5xqc7w6xm79lha27glmd0vdt32a3fj2"),
|
("crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove", "nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94"),
|
||||||
("acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel", "punk1h5hgn94nsq4kh99rjj794hr5h5q6yfm22mcqqn"),
|
("acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel", "nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv"),
|
||||||
("step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball", "punk17n9flp6jflljg6fp05dsy07wcprf2uuujse962")
|
("step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball", "nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4")
|
||||||
];
|
];
|
||||||
|
|
||||||
for (mnemonic, address) in mnemonic_address.into_iter() {
|
for (mnemonic, address) in mnemonic_address.into_iter() {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match option_env!("NETWORK") {
|
||||||
|
None | Some("milhon") => println!("cargo:rustc-cfg=network=\"milhon\"",),
|
||||||
|
Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",),
|
||||||
|
Some("qa") => println!("cargo:rustc-cfg=network=\"qa\""),
|
||||||
|
_ => panic!("No such network"),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,15 @@ use time::OffsetDateTime;
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub mod eth_contract;
|
pub mod eth_contract;
|
||||||
|
#[cfg(network = "milhon")]
|
||||||
|
pub mod milhon;
|
||||||
|
#[cfg(network = "sandbox")]
|
||||||
|
pub mod sandbox;
|
||||||
|
|
||||||
|
#[cfg(network = "milhon")]
|
||||||
|
pub use milhon::*;
|
||||||
|
#[cfg(network = "sandbox")]
|
||||||
|
pub use sandbox::*;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct ValidatorDetails {
|
pub struct ValidatorDetails {
|
||||||
@@ -38,6 +47,7 @@ impl ValidatorDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(network = "milhon")]
|
||||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||||
vec![
|
vec![
|
||||||
ValidatorDetails::new(
|
ValidatorDetails::new(
|
||||||
@@ -48,6 +58,14 @@ pub fn default_validators() -> Vec<ValidatorDetails> {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(network = "sandbox")]
|
||||||
|
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||||
|
vec![ValidatorDetails::new(
|
||||||
|
"https://sandbox-validator.nymtech.net",
|
||||||
|
Some("https://sandbox-validator.nymtech.net/api"),
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn default_nymd_endpoints() -> Vec<Url> {
|
pub fn default_nymd_endpoints() -> Vec<Url> {
|
||||||
default_validators()
|
default_validators()
|
||||||
.iter()
|
.iter()
|
||||||
@@ -62,10 +80,7 @@ pub fn default_api_endpoints() -> Vec<Url> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen";
|
// Ethereum constants used for token bridge
|
||||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "";
|
|
||||||
pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
|
|
||||||
|
|
||||||
/// How much bandwidth (in bytes) one token can buy
|
/// How much bandwidth (in bytes) one token can buy
|
||||||
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
|
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
|
||||||
/// How many ERC20 tokens should be burned to buy bandwidth
|
/// How many ERC20 tokens should be burned to buy bandwidth
|
||||||
@@ -73,20 +88,10 @@ pub const TOKENS_TO_BURN: u64 = 10;
|
|||||||
/// Default bandwidth (in bytes) that we try to buy
|
/// Default bandwidth (in bytes) that we try to buy
|
||||||
pub const BANDWIDTH_VALUE: u64 = TOKENS_TO_BURN * BYTES_PER_TOKEN;
|
pub const BANDWIDTH_VALUE: u64 = TOKENS_TO_BURN * BYTES_PER_TOKEN;
|
||||||
|
|
||||||
// Ethereum constants used for token bridge
|
|
||||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
|
|
||||||
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
|
|
||||||
pub const ETH_MIN_BLOCK_DEPTH: usize = 7;
|
pub const ETH_MIN_BLOCK_DEPTH: usize = 7;
|
||||||
pub const COSMOS_CONTRACT_ADDRESS: &str = "punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82";
|
|
||||||
// Name of the event triggered by the eth contract. If the event name is changed,
|
|
||||||
// this would also need to be changed; It is currently tested against the json abi
|
|
||||||
pub const ETH_EVENT_NAME: &str = "Burned";
|
|
||||||
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
|
|
||||||
|
|
||||||
/// Defaults Cosmos Hub/ATOM path
|
/// Defaults Cosmos Hub/ATOM path
|
||||||
pub const COSMOS_DERIVATION_PATH: &str = "m/44'/118'/0'/0/0";
|
pub const COSMOS_DERIVATION_PATH: &str = "m/44'/118'/0'/0/0";
|
||||||
pub const BECH32_PREFIX: &str = "punk";
|
|
||||||
pub const DENOM: &str = "upunk";
|
|
||||||
// as set by validators in their configs
|
// as set by validators in their configs
|
||||||
// (note that the 'amount' postfix is relevant here as the full gas price also includes denom)
|
// (note that the 'amount' postfix is relevant here as the full gas price also includes denom)
|
||||||
pub const GAS_PRICE_AMOUNT: f64 = 0.025;
|
pub const GAS_PRICE_AMOUNT: f64 = 0.025;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
pub const BECH32_PREFIX: &str = "punk";
|
||||||
|
pub const DENOM: &str = "upunk";
|
||||||
|
|
||||||
|
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen";
|
||||||
|
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "";
|
||||||
|
pub const COSMOS_CONTRACT_ADDRESS: &str = "punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82";
|
||||||
|
pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
|
||||||
|
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||||
|
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
|
||||||
|
|
||||||
|
// Name of the event triggered by the eth contract. If the event name is changed,
|
||||||
|
// this would also need to be changed; It is currently tested against the json abi
|
||||||
|
pub const ETH_EVENT_NAME: &str = "Burned";
|
||||||
|
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
pub const BECH32_PREFIX: &str = "nymt";
|
||||||
|
pub const DENOM: &str = "unymt";
|
||||||
|
|
||||||
|
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "nymt14hj2tavq8fpesdwxxcu44rty3hh90vhuysqrsr";
|
||||||
|
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s";
|
||||||
|
pub const COSMOS_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
|
||||||
|
pub const REWARDING_VALIDATOR_ADDRESS: &str = "nymt17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e";
|
||||||
|
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||||
|
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
|
||||||
|
|
||||||
|
// Name of the event triggered by the eth contract. If the event name is changed,
|
||||||
|
// this would also need to be changed; It is currently tested against the json abi
|
||||||
|
pub const ETH_EVENT_NAME: &str = "Burned";
|
||||||
|
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
|
||||||
@@ -282,8 +282,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
|
|||||||
}
|
}
|
||||||
#[entry_point]
|
#[entry_point]
|
||||||
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||||
todo!("ACTIVE_STATE_WORK_FACTOR to State");
|
Ok(Default::default())
|
||||||
// Ok(Default::default())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ serde_json = "1.0.66"
|
|||||||
tokio = {version = "1.9.0", features = ["full"] }
|
tokio = {version = "1.9.0", features = ["full"] }
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
schemars = { version = "0.8", features = ["preserve_order"] }
|
schemars = { version = "0.8", features = ["preserve_order"] }
|
||||||
okapi = { version = "0.6.0-alpha-1", features = ["derive_json_schema"] }
|
okapi = { version = "0.7.0-rc.1", features = ["impl_json_schema"] }
|
||||||
rocket_okapi = "0.7.0-alpha-1"
|
rocket_okapi = { version = "0.8.0-rc.1", features = ["swagger"] }
|
||||||
log = "0.4.0"
|
log = "0.4.0"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
thiserror = "1.0.29"
|
thiserror = "1.0.29"
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ impl GeoLocateTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn start(mut self) {
|
pub(crate) fn start(mut self) {
|
||||||
|
if ::std::env::var("GEO_IP_SERVICE_API_KEY").is_err() {
|
||||||
|
error!(
|
||||||
|
"Env var GEO_IP_SERVICE_API_KEY is not set. Geolocation tasks will not be started."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
info!("Spawning mix node locator task runner...");
|
info!("Spawning mix node locator task runner...");
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut interval_timer = tokio::time::interval(std::time::Duration::from_millis(50));
|
let mut interval_timer = tokio::time::interval(std::time::Duration::from_millis(50));
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ use crate::country_statistics::country_nodes_distribution::CountryNodesDistribut
|
|||||||
use crate::state::ExplorerApiStateContext;
|
use crate::state::ExplorerApiStateContext;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::{Route, State};
|
use rocket::{Route, State};
|
||||||
|
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||||
|
use rocket_okapi::openapi_get_routes_spec;
|
||||||
|
use rocket_okapi::settings::OpenApiSettings;
|
||||||
|
|
||||||
pub fn country_statistics_make_default_routes() -> Vec<Route> {
|
pub fn country_statistics_make_default_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
|
||||||
routes_with_openapi![index]
|
openapi_get_routes_spec![settings: index]
|
||||||
}
|
}
|
||||||
|
|
||||||
// We could either separate stuff by structure (like this, http is separate), or we could just
|
// We could either separate stuff by structure (like this, http is separate), or we could just
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use log::info;
|
use log::info;
|
||||||
use rocket::http::Method;
|
use rocket::http::Method;
|
||||||
use rocket::Request;
|
use rocket::{Build, Request, Rocket};
|
||||||
use rocket_cors::{AllowedHeaders, AllowedOrigins};
|
use rocket_cors::{AllowedHeaders, AllowedOrigins};
|
||||||
use rocket_okapi::swagger_ui::make_swagger_ui;
|
use rocket_okapi::swagger_ui::make_swagger_ui;
|
||||||
|
|
||||||
use crate::country_statistics::http::country_statistics_make_default_routes;
|
use crate::country_statistics::http::country_statistics_make_default_routes;
|
||||||
use crate::http::swagger::get_docs;
|
use crate::http::swagger::get_docs;
|
||||||
use crate::mix_node::http::mix_node_make_default_routes;
|
use crate::mix_node::http::mix_node_make_default_routes;
|
||||||
|
use crate::mix_nodes::http::mix_nodes_make_default_routes;
|
||||||
use crate::ping::http::ping_make_default_routes;
|
use crate::ping::http::ping_make_default_routes;
|
||||||
use crate::state::ExplorerApiStateContext;
|
use crate::state::ExplorerApiStateContext;
|
||||||
|
|
||||||
@@ -15,7 +16,11 @@ mod swagger;
|
|||||||
pub(crate) fn start(state: ExplorerApiStateContext) {
|
pub(crate) fn start(state: ExplorerApiStateContext) {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
info!("Starting up...");
|
info!("Starting up...");
|
||||||
|
configure_rocket(state).launch().await
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_rocket(state: ExplorerApiStateContext) -> Rocket<Build> {
|
||||||
let allowed_origins = AllowedOrigins::all();
|
let allowed_origins = AllowedOrigins::all();
|
||||||
|
|
||||||
// You can also deserialize this
|
// You can also deserialize this
|
||||||
@@ -29,19 +34,25 @@ pub(crate) fn start(state: ExplorerApiStateContext) {
|
|||||||
.to_cors()
|
.to_cors()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let openapi_settings = rocket_okapi::settings::OpenApiSettings::default();
|
||||||
let config = rocket::config::Config::release_default();
|
let config = rocket::config::Config::release_default();
|
||||||
rocket::build()
|
let mut building_rocket = rocket::build().configure(config);
|
||||||
.configure(config)
|
|
||||||
.mount("/countries", country_statistics_make_default_routes())
|
mount_endpoints_and_merged_docs! {
|
||||||
.mount("/ping", ping_make_default_routes())
|
building_rocket,
|
||||||
.mount("/mix-node", mix_node_make_default_routes())
|
"/v1".to_owned(),
|
||||||
|
openapi_settings,
|
||||||
|
"/ping" => ping_make_default_routes(&openapi_settings),
|
||||||
|
"/countries" => country_statistics_make_default_routes(&openapi_settings),
|
||||||
|
"/mix-node" => mix_node_make_default_routes(&openapi_settings),
|
||||||
|
"/mix-nodes" => mix_nodes_make_default_routes(&openapi_settings),
|
||||||
|
};
|
||||||
|
|
||||||
|
building_rocket
|
||||||
.mount("/swagger", make_swagger_ui(&get_docs()))
|
.mount("/swagger", make_swagger_ui(&get_docs()))
|
||||||
.register("/", catchers![not_found])
|
.register("/", catchers![not_found])
|
||||||
.manage(state)
|
.manage(state)
|
||||||
.attach(cors)
|
.attach(cors)
|
||||||
.launch()
|
|
||||||
.await
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[catch(404)]
|
#[catch(404)]
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
use rocket_okapi::swagger_ui::{SwaggerUIConfig, UrlObject};
|
use rocket_okapi::swagger_ui::SwaggerUIConfig;
|
||||||
|
|
||||||
pub(crate) fn get_docs() -> SwaggerUIConfig {
|
pub(crate) fn get_docs() -> SwaggerUIConfig {
|
||||||
SwaggerUIConfig {
|
SwaggerUIConfig {
|
||||||
urls: vec![
|
url: "../v1/openapi.json".to_owned(),
|
||||||
UrlObject::new("Country statistics", "/countries/openapi.json"),
|
|
||||||
UrlObject::new("Node ping", "/ping/openapi.json"),
|
|
||||||
UrlObject::new("Mix node", "/mix-node/openapi.json"),
|
|
||||||
],
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ impl ExplorerApi {
|
|||||||
async fn run(&mut self) {
|
async fn run(&mut self) {
|
||||||
info!("Explorer API starting up...");
|
info!("Explorer API starting up...");
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Using validator API - {}",
|
||||||
|
network_defaults::default_api_endpoints()[0].clone()
|
||||||
|
);
|
||||||
|
|
||||||
// spawn concurrent tasks
|
// spawn concurrent tasks
|
||||||
mix_nodes::tasks::MixNodesTasks::new(self.state.clone()).start();
|
mix_nodes::tasks::MixNodesTasks::new(self.state.clone()).start();
|
||||||
country_statistics::distribution::CountryStatisticsDistributionTask::new(
|
country_statistics::distribution::CountryStatisticsDistributionTask::new(
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use reqwest::Error as ReqwestError;
|
use reqwest::Error as ReqwestError;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::{Route, State};
|
use rocket::{Route, State};
|
||||||
|
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||||
|
use rocket_okapi::openapi_get_routes_spec;
|
||||||
|
use rocket_okapi::settings::OpenApiSettings;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use mixnet_contract::{Addr, Coin, Delegation, Layer, MixNode};
|
use mixnet_contract::{Addr, Coin, Delegation, Layer, MixNode};
|
||||||
@@ -9,13 +12,12 @@ use crate::mix_node::models::{NodeDescription, NodeStats};
|
|||||||
use crate::mix_nodes::{get_mixnode_delegations, get_single_mixnode_delegations, Location};
|
use crate::mix_nodes::{get_mixnode_delegations, get_single_mixnode_delegations, Location};
|
||||||
use crate::state::ExplorerApiStateContext;
|
use crate::state::ExplorerApiStateContext;
|
||||||
|
|
||||||
pub fn mix_node_make_default_routes() -> Vec<Route> {
|
pub fn mix_node_make_default_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
|
||||||
routes_with_openapi![
|
openapi_get_routes_spec![
|
||||||
get_delegations,
|
settings: get_delegations,
|
||||||
get_all_delegations,
|
get_all_delegations,
|
||||||
get_description,
|
get_description,
|
||||||
get_stats,
|
get_stats,
|
||||||
list
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,14 +31,6 @@ pub(crate) struct PrettyMixNodeBondWithLocation {
|
|||||||
pub mix_node: MixNode,
|
pub mix_node: MixNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[openapi(tag = "mix_node")]
|
|
||||||
#[get("/")]
|
|
||||||
pub(crate) async fn list(
|
|
||||||
state: &State<ExplorerApiStateContext>,
|
|
||||||
) -> Json<Vec<PrettyMixNodeBondWithLocation>> {
|
|
||||||
Json(state.inner.mix_nodes.get_mixnodes_with_location().await)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "mix_node")]
|
#[openapi(tag = "mix_node")]
|
||||||
#[get("/<pubkey>/delegations")]
|
#[get("/<pubkey>/delegations")]
|
||||||
pub(crate) async fn get_delegations(pubkey: &str) -> Json<Vec<Delegation>> {
|
pub(crate) async fn get_delegations(pubkey: &str) -> Json<Vec<Delegation>> {
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
use rocket::serde::json::Json;
|
||||||
|
use rocket::{Route, State};
|
||||||
|
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||||
|
use rocket_okapi::openapi_get_routes_spec;
|
||||||
|
use rocket_okapi::settings::OpenApiSettings;
|
||||||
|
|
||||||
|
use crate::mix_node::http::PrettyMixNodeBondWithLocation;
|
||||||
|
use crate::state::ExplorerApiStateContext;
|
||||||
|
|
||||||
|
pub fn mix_nodes_make_default_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
|
||||||
|
openapi_get_routes_spec![settings: list]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[openapi(tag = "mix_nodes")]
|
||||||
|
#[get("/")]
|
||||||
|
pub(crate) async fn list(
|
||||||
|
state: &State<ExplorerApiStateContext>,
|
||||||
|
) -> Json<Vec<PrettyMixNodeBondWithLocation>> {
|
||||||
|
Json(state.inner.mix_nodes.get_mixnodes_with_location().await)
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub(crate) mod http;
|
||||||
pub(crate) mod tasks;
|
pub(crate) mod tasks;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::{Route, State};
|
use rocket::{Route, State};
|
||||||
|
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||||
|
use rocket_okapi::openapi_get_routes_spec;
|
||||||
|
use rocket_okapi::settings::OpenApiSettings;
|
||||||
|
|
||||||
use mixnet_contract::MixNodeBond;
|
use mixnet_contract::MixNodeBond;
|
||||||
|
|
||||||
@@ -12,8 +15,8 @@ use crate::state::ExplorerApiStateContext;
|
|||||||
|
|
||||||
const CONNECTION_TIMEOUT_SECONDS: Duration = Duration::from_secs(10);
|
const CONNECTION_TIMEOUT_SECONDS: Duration = Duration::from_secs(10);
|
||||||
|
|
||||||
pub fn ping_make_default_routes() -> Vec<Route> {
|
pub fn ping_make_default_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
|
||||||
routes_with_openapi![index]
|
openapi_get_routes_spec![settings: index]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[openapi(tag = "ping")]
|
#[openapi(tag = "ping")]
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
EXPLORER_API_URL=https://testnet-milhon-explorer.nymtech.net
|
|
||||||
VALIDATOR_API_URL=https://testnet-milhon-validator1.nymtech.net
|
|
||||||
BIG_DIPPER_URL=https://testnet-milhon-blocks.nymtech.net
|
|
||||||
+5
-3
@@ -1,3 +1,5 @@
|
|||||||
EXPLORER_API_URL=https://testnet-milhon-explorer.nymtech.net
|
EXPLORER_API_URL=https://sandbox-explorer.nymtech.net/api/v1
|
||||||
VALIDATOR_API_URL=https://testnet-milhon-validator1.nymtech.net
|
VALIDATOR_API_URL=https://sandbox-validator.nymtech.net
|
||||||
BIG_DIPPER_URL=https://testnet-milhon-blocks.nymtech.net
|
BIG_DIPPER_URL=https://sandbox-blocks.nymtech.net
|
||||||
|
CURRENCY_DENOM=unymt
|
||||||
|
CURRENCY_STAKING_DENOM=unyxt
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
// master APIs
|
// master APIs
|
||||||
export const MASTER_URL = process.env.EXPLORER_API_URL;
|
export const API_BASE_URL = process.env.EXPLORER_API_URL;
|
||||||
export const MASTER_VALIDATOR_URL = process.env.VALIDATOR_API_URL;
|
export const VALIDATOR_API_BASE_URL = process.env.VALIDATOR_API_URL;
|
||||||
export const BIG_DIPPER = process.env.BIG_DIPPER_URL;
|
export const BIG_DIPPER = process.env.BIG_DIPPER_URL;
|
||||||
|
|
||||||
// specific API routes
|
// specific API routes
|
||||||
export const MIXNODE_PING = `${MASTER_URL}/api/ping`;
|
export const MIXNODE_PING = `${API_BASE_URL}/ping`;
|
||||||
export const MIXNODES_API = `${MASTER_URL}/api/mix-node`;
|
export const MIXNODES_API = `${API_BASE_URL}/mix-nodes`;
|
||||||
export const GATEWAYS_API = `${MASTER_VALIDATOR_URL}/api/v1/gateways`;
|
export const MIXNODE_API = `${API_BASE_URL}/mix-node`;
|
||||||
export const VALIDATORS_API = `${MASTER_VALIDATOR_URL}/validators`;
|
export const GATEWAYS_API = `${VALIDATOR_API_BASE_URL}/api/v1/gateways`;
|
||||||
export const BLOCK_API = `${MASTER_VALIDATOR_URL}/block`;
|
export const VALIDATORS_API = `${VALIDATOR_API_BASE_URL}/validators`;
|
||||||
export const COUNTRY_DATA_API = `${MASTER_URL}/api/countries`;
|
export const BLOCK_API = `${VALIDATOR_API_BASE_URL}/block`;
|
||||||
export const UPTIME_STORY_API = `${MASTER_VALIDATOR_URL}/api/v1/status/mixnode`; // add ID then '/history' to this.
|
export const COUNTRY_DATA_API = `${API_BASE_URL}/countries`;
|
||||||
|
export const UPTIME_STORY_API = `${VALIDATOR_API_BASE_URL}/api/v1/status/mixnode`; // add ID then '/history' to this.
|
||||||
|
|
||||||
// errors
|
// errors
|
||||||
export const MIXNODE_API_ERROR =
|
export const MIXNODE_API_ERROR =
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
COUNTRY_DATA_API,
|
COUNTRY_DATA_API,
|
||||||
MIXNODE_PING,
|
MIXNODE_PING,
|
||||||
UPTIME_STORY_API,
|
UPTIME_STORY_API,
|
||||||
|
MIXNODE_API,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -87,10 +88,10 @@ export class Api {
|
|||||||
static fetchDelegationsById = async (
|
static fetchDelegationsById = async (
|
||||||
id: string,
|
id: string,
|
||||||
): Promise<DelegationsResponse> =>
|
): Promise<DelegationsResponse> =>
|
||||||
(await fetch(`${MIXNODES_API}/${id}/delegations`)).json();
|
(await fetch(`${MIXNODE_API}/${id}/delegations`)).json();
|
||||||
|
|
||||||
static fetchStatsById = async (id: string): Promise<StatsResponse> =>
|
static fetchStatsById = async (id: string): Promise<StatsResponse> =>
|
||||||
(await fetch(`${MIXNODES_API}/${id}/stats`)).json();
|
(await fetch(`${MIXNODE_API}/${id}/stats`)).json();
|
||||||
|
|
||||||
static fetchStatusById = async (id: string): Promise<StatusResponse> =>
|
static fetchStatusById = async (id: string): Promise<StatusResponse> =>
|
||||||
(await fetch(`${MIXNODE_PING}/${id}`)).json();
|
(await fetch(`${MIXNODE_PING}/${id}`)).json();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { printableCoin } from '@nymproject/nym-validator-client';
|
import { Alert, Box, CircularProgress, useMediaQuery } from '@mui/material';
|
||||||
import { Alert, CircularProgress, useMediaQuery, Box } from '@mui/material';
|
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from '@mui/material/styles';
|
||||||
import Table from '@mui/material/Table';
|
import Table from '@mui/material/Table';
|
||||||
import TableBody from '@mui/material/TableBody';
|
import TableBody from '@mui/material/TableBody';
|
||||||
@@ -11,6 +10,7 @@ import TableRow from '@mui/material/TableRow';
|
|||||||
import Paper from '@mui/material/Paper';
|
import Paper from '@mui/material/Paper';
|
||||||
import { useMainContext } from 'src/context/main';
|
import { useMainContext } from 'src/context/main';
|
||||||
import { ExpandMore } from '@mui/icons-material';
|
import { ExpandMore } from '@mui/icons-material';
|
||||||
|
import { currencyToString } from '../utils/currency';
|
||||||
|
|
||||||
export const BondBreakdownTable: React.FC = () => {
|
export const BondBreakdownTable: React.FC = () => {
|
||||||
const { mixnodeDetailInfo, delegations } = useMainContext();
|
const { mixnodeDetailInfo, delegations } = useMainContext();
|
||||||
@@ -34,24 +34,23 @@ export const BondBreakdownTable: React.FC = () => {
|
|||||||
const thisMixnode = mixnodeDetailInfo?.data[0];
|
const thisMixnode = mixnodeDetailInfo?.data[0];
|
||||||
|
|
||||||
// delegations
|
// delegations
|
||||||
const decimalisedDelegations = printableCoin({
|
const decimalisedDelegations = currencyToString(
|
||||||
amount: thisMixnode.total_delegation.amount.toString(),
|
thisMixnode.total_delegation.amount.toString(),
|
||||||
denom: thisMixnode.total_delegation.denom,
|
thisMixnode.total_delegation.denom,
|
||||||
});
|
);
|
||||||
|
|
||||||
// pledges
|
// pledges
|
||||||
const decimalisedPledges = printableCoin({
|
const decimalisedPledges = currencyToString(
|
||||||
amount: thisMixnode.bond_amount.amount.toString(),
|
thisMixnode.pledge_amount.amount.toString(),
|
||||||
denom: thisMixnode.bond_amount.denom,
|
thisMixnode.pledge_amount.denom,
|
||||||
});
|
);
|
||||||
|
|
||||||
// bonds total (del + pledges)
|
// bonds total (del + pledges)
|
||||||
const pledgesSum = Number(thisMixnode.bond_amount.amount);
|
const pledgesSum = Number(thisMixnode.pledge_amount.amount);
|
||||||
const delegationsSum = Number(thisMixnode.total_delegation.amount);
|
const delegationsSum = Number(thisMixnode.total_delegation.amount);
|
||||||
const bondsTotal = printableCoin({
|
const bondsTotal = currencyToString(
|
||||||
amount: (delegationsSum + pledgesSum).toString(),
|
(delegationsSum + pledgesSum).toString(),
|
||||||
denom: 'upunk',
|
);
|
||||||
});
|
|
||||||
|
|
||||||
setBonds({
|
setBonds({
|
||||||
delegations: decimalisedDelegations,
|
delegations: decimalisedDelegations,
|
||||||
@@ -89,7 +88,7 @@ export const BondBreakdownTable: React.FC = () => {
|
|||||||
mixnodeDetailInfo.data[0].total_delegation.amount,
|
mixnodeDetailInfo.data[0].total_delegation.amount,
|
||||||
);
|
);
|
||||||
const rawPledgeAmount = Number(
|
const rawPledgeAmount = Number(
|
||||||
mixnodeDetailInfo.data[0].bond_amount.amount,
|
mixnodeDetailInfo.data[0].pledge_amount.amount,
|
||||||
);
|
);
|
||||||
const rawTotalBondsAmount = rawDelegationAmount + rawPledgeAmount;
|
const rawTotalBondsAmount = rawDelegationAmount + rawPledgeAmount;
|
||||||
return ((num * 100) / rawTotalBondsAmount).toFixed(1);
|
return ((num * 100) / rawTotalBondsAmount).toFixed(1);
|
||||||
@@ -203,7 +202,7 @@ export const BondBreakdownTable: React.FC = () => {
|
|||||||
{owner}
|
{owner}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="left">
|
<TableCell align="left">
|
||||||
{printableCoin({ amount: amount.toString(), denom })}
|
{currencyToString(amount.toString(), denom)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="left">
|
<TableCell align="left">
|
||||||
{calcBondPercentage(amount)}%
|
{calcBondPercentage(amount)}%
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { printableCoin } from '@nymproject/nym-validator-client';
|
|
||||||
import { cellStyles } from './Universal-DataGrid';
|
import { cellStyles } from './Universal-DataGrid';
|
||||||
import { MixnodeRowType } from '../utils/index';
|
import { MixnodeRowType } from '../utils/index';
|
||||||
|
import { currencyToString } from '../utils/currency';
|
||||||
|
|
||||||
export type ColumnsType = {
|
export type ColumnsType = {
|
||||||
field: string;
|
field: string;
|
||||||
@@ -28,7 +28,7 @@ export interface UniversalTableProps {
|
|||||||
|
|
||||||
function formatCellValues(val: string | number, field: string) {
|
function formatCellValues(val: string | number, field: string) {
|
||||||
if (field === 'bond') {
|
if (field === 'bond') {
|
||||||
return printableCoin({ amount: val.toString(), denom: 'upunk' });
|
return currencyToString(val.toString());
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Button, Card, Grid, Typography } from '@mui/material';
|
import { Button, Card, Grid, Typography } from '@mui/material';
|
||||||
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
|
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
|
||||||
import { printableCoin } from '@nymproject/nym-validator-client';
|
|
||||||
import { SelectChangeEvent } from '@mui/material/Select';
|
import { SelectChangeEvent } from '@mui/material/Select';
|
||||||
import { useMainContext } from 'src/context/main';
|
import { useMainContext } from 'src/context/main';
|
||||||
import { gatewayToGridRow } from 'src/utils';
|
import { gatewayToGridRow } from 'src/utils';
|
||||||
@@ -13,6 +12,7 @@ import {
|
|||||||
cellStyles,
|
cellStyles,
|
||||||
UniversalDataGrid,
|
UniversalDataGrid,
|
||||||
} from 'src/components/Universal-DataGrid';
|
} from 'src/components/Universal-DataGrid';
|
||||||
|
import { currencyToString } from '../../utils/currency';
|
||||||
|
|
||||||
export const PageGateways: React.FC = () => {
|
export const PageGateways: React.FC = () => {
|
||||||
const { gateways } = useMainContext();
|
const { gateways } = useMainContext();
|
||||||
@@ -79,17 +79,11 @@ export const PageGateways: React.FC = () => {
|
|||||||
renderHeader: () => <CustomColumnHeading headingTitle="Pledge" />,
|
renderHeader: () => <CustomColumnHeading headingTitle="Pledge" />,
|
||||||
headerClassName: 'MuiDataGrid-header-override',
|
headerClassName: 'MuiDataGrid-header-override',
|
||||||
headerAlign: 'left',
|
headerAlign: 'left',
|
||||||
renderCell: (params: GridRenderCellParams) => {
|
renderCell: (params: GridRenderCellParams) => (
|
||||||
const bondAsPunk = printableCoin({
|
|
||||||
amount: params.value as string,
|
|
||||||
denom: 'upunk',
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<Typography sx={cellStyles} data-testid="pledge-amount">
|
<Typography sx={cellStyles} data-testid="pledge-amount">
|
||||||
{bondAsPunk}
|
{currencyToString(params.value)}
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'host',
|
field: 'host',
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
|
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
|
||||||
import { printableCoin } from '@nymproject/nym-validator-client';
|
|
||||||
import { Button, Grid, Link as MuiLink, Card } from '@mui/material';
|
import { Button, Grid, Link as MuiLink, Card } from '@mui/material';
|
||||||
import { Link as RRDLink } from 'react-router-dom';
|
import { Link as RRDLink } from 'react-router-dom';
|
||||||
import { SelectChangeEvent } from '@mui/material/Select';
|
import { SelectChangeEvent } from '@mui/material/Select';
|
||||||
@@ -15,6 +14,7 @@ import {
|
|||||||
UniversalDataGrid,
|
UniversalDataGrid,
|
||||||
cellStyles,
|
cellStyles,
|
||||||
} from 'src/components/Universal-DataGrid';
|
} from 'src/components/Universal-DataGrid';
|
||||||
|
import { currencyToString } from '../../utils/currency';
|
||||||
|
|
||||||
export const PageMixnodes: React.FC = () => {
|
export const PageMixnodes: React.FC = () => {
|
||||||
const { mixnodes } = useMainContext();
|
const { mixnodes } = useMainContext();
|
||||||
@@ -92,21 +92,15 @@ export const PageMixnodes: React.FC = () => {
|
|||||||
headerClassName: 'MuiDataGrid-header-override',
|
headerClassName: 'MuiDataGrid-header-override',
|
||||||
width: 150,
|
width: 150,
|
||||||
headerAlign: 'left',
|
headerAlign: 'left',
|
||||||
renderCell: (params: GridRenderCellParams) => {
|
renderCell: (params: GridRenderCellParams) => (
|
||||||
const bondAsPunk = printableCoin({
|
|
||||||
amount: params.value as string,
|
|
||||||
denom: 'upunk',
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<MuiLink
|
<MuiLink
|
||||||
sx={cellStyles}
|
sx={cellStyles}
|
||||||
component={RRDLink}
|
component={RRDLink}
|
||||||
to={`/network-components/mixnodes/${params.row.identity_key}`}
|
to={`/network-components/mixnodes/${params.row.identity_key}`}
|
||||||
>
|
>
|
||||||
{bondAsPunk}
|
{currencyToString(params.value)}
|
||||||
</MuiLink>
|
</MuiLink>
|
||||||
);
|
),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'location',
|
field: 'location',
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ export interface ClientConfig {
|
|||||||
|
|
||||||
export interface MixNode {
|
export interface MixNode {
|
||||||
host: string;
|
host: string;
|
||||||
location: string;
|
mix_port: number;
|
||||||
|
http_api_port: number;
|
||||||
|
verloc_port: number;
|
||||||
sphinx_key: string;
|
sphinx_key: string;
|
||||||
identity_key: string;
|
identity_key: string;
|
||||||
version: string;
|
version: string;
|
||||||
mix_port: number;
|
profit_margin_percent: number;
|
||||||
verloc_port: number;
|
location: string;
|
||||||
http_api_port: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Gateway {
|
export interface Gateway {
|
||||||
@@ -32,7 +33,7 @@ export interface Amount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MixNodeResponseItem {
|
export interface MixNodeResponseItem {
|
||||||
bond_amount: Amount;
|
pledge_amount: Amount;
|
||||||
total_delegation: Amount;
|
total_delegation: Amount;
|
||||||
owner: string;
|
owner: string;
|
||||||
layer: string;
|
layer: string;
|
||||||
@@ -74,7 +75,7 @@ export type MixNodeHistoryResponse = StatsResponse;
|
|||||||
|
|
||||||
export interface GatewayResponseItem {
|
export interface GatewayResponseItem {
|
||||||
block_height: number;
|
block_height: number;
|
||||||
bond_amount: Amount;
|
pledge_amount: Amount;
|
||||||
total_delegation: Amount;
|
total_delegation: Amount;
|
||||||
owner: string;
|
owner: string;
|
||||||
gateway: Gateway;
|
gateway: Gateway;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { printableCoin } from '@nymproject/nym-validator-client';
|
||||||
|
|
||||||
|
const DENOM = process.env.CURRENCY_DENOM || 'unym';
|
||||||
|
const DENOM_STAKING = process.env.CURRENCY_STAKING_DENOM || 'unyx';
|
||||||
|
|
||||||
|
export const currencyToString = (amount: string, denom: string = DENOM) =>
|
||||||
|
printableCoin({
|
||||||
|
amount,
|
||||||
|
denom,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const stakingCurrencyToString = (
|
||||||
|
amount: string,
|
||||||
|
denom: string = DENOM_STAKING,
|
||||||
|
) =>
|
||||||
|
printableCoin({
|
||||||
|
amount,
|
||||||
|
denom,
|
||||||
|
});
|
||||||
@@ -69,7 +69,7 @@ export function mixnodeToGridRow(arrayOfMixnodes: MixNodeResponse): any {
|
|||||||
return !arrayOfMixnodes
|
return !arrayOfMixnodes
|
||||||
? []
|
? []
|
||||||
: arrayOfMixnodes.map((mn) => {
|
: arrayOfMixnodes.map((mn) => {
|
||||||
const pledge = Number(mn.bond_amount.amount) || 0;
|
const pledge = Number(mn.pledge_amount.amount) || 0;
|
||||||
const delegations = Number(mn.total_delegation.amount) || 0;
|
const delegations = Number(mn.total_delegation.amount) || 0;
|
||||||
const totalBond = pledge + delegations;
|
const totalBond = pledge + delegations;
|
||||||
const selfPercentage = ((pledge * 100) / totalBond).toFixed(2);
|
const selfPercentage = ((pledge * 100) / totalBond).toFixed(2);
|
||||||
@@ -96,7 +96,7 @@ export function gatewayToGridRow(
|
|||||||
owner: gw.owner,
|
owner: gw.owner,
|
||||||
identity_key: gw.gateway.identity_key || '',
|
identity_key: gw.gateway.identity_key || '',
|
||||||
location: gw?.gateway?.location || '',
|
location: gw?.gateway?.location || '',
|
||||||
bond: gw.bond_amount.amount || 0,
|
bond: gw.pledge_amount.amount || 0,
|
||||||
host: gw.gateway.host || '',
|
host: gw.gateway.host || '',
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user