Compare commits

...

12 Commits

Author SHA1 Message Date
Bogdan-Ștefan Neacșu ca98a17db3 Enable migrate entry point 2021-12-17 13:19:14 +02:00
Bogdan-Ștefan Neacșu 11f56cd0d7 Reinstate signature check 2021-12-17 13:19:10 +02:00
Bogdan-Ștefan Neacșu 185884f546 Revert "Do not set proxy only for this time"
This reverts commit 47946ad79e.
2021-12-17 13:19:06 +02:00
Mark Sinclair ae0883241e Network Explorer: change prod env to round robin DNS 2021-12-17 13:07:16 +02:00
Mark Sinclair 11baa99c4b Network Explorer improvements:
- fix up API urls after Network Explorer API changes
- set currency denominations in `.env` file
- set API endpoints in `.env` file
2021-12-17 13:07:16 +02:00
Mark Sinclair 8bc23434ab Network Explorer API improvements:
- upgrade `okapi` for swagger generation across multiple resources
- switched `GET mix-node` to `GET mix-nodes`
- added error message when no geolocation env var is set and process continues
2021-12-17 13:07:16 +02:00
Mark Sinclair 8f6daf1e03 Network Explorer: configure URLs with .env file 2021-12-17 13:07:15 +02:00
Bogdan-Ștefan Neacșu 7f63377d22 Update contract addresses 2021-12-17 13:03:28 +02:00
Bogdan-Ștefan Neacșu 46cb3eca38 Do not set proxy only for this time 2021-12-17 13:02:01 +02:00
Bogdan-Ștefan Neacșu 7b22872c6b Short node identity signature check
Fix tests
2021-12-17 13:02:01 +02:00
Bogdan-Ștefan Neacșu 3342cb13c7 Update network defaults 2021-12-17 13:01:59 +02:00
Bogdan-Ștefan Neacșu 3cd5fc3b22 Make develop branch agnostic of the network 2021-12-17 12:48:29 +02:00
28 changed files with 248 additions and 148 deletions
Generated
+9 -6
View File
@@ -3972,10 +3972,11 @@ dependencies = [
[[package]]
name = "okapi"
version = "0.6.0-alpha-1"
version = "0.7.0-rc.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb085e00daf8d75b9dbf0ffdb4738e69503e28898d9641fa8bdc6ad536c7bcf4"
checksum = "ce66b6366e049880a35c378123fddb630b1a1a3c37fa1ca70caaf4a09f6e2893"
dependencies = [
"log",
"schemars",
"serde",
"serde_json",
@@ -5212,10 +5213,12 @@ dependencies = [
[[package]]
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"
checksum = "8b2f4f48fb070f9f6c56d5663df5fa8a514406207744f4abd84661bfb24efd7d"
checksum = "0025aa04994af8cd8e1fcdd5a73579a395c941ae090ecb0a39b41cca7e237a20"
dependencies = [
"either",
"log",
"okapi",
"rocket",
"rocket_okapi_codegen",
@@ -5226,9 +5229,9 @@ dependencies = [
[[package]]
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"
checksum = "88ccf1550e1c806461a6b08e2ab64eb10701d41bf50bde59ab9aa3a57ab14d41"
checksum = "dc114779fc27afb78179233e966f469e47fd7a98dc15181cff2574cdddb65612"
dependencies = [
"darling 0.13.0",
"proc-macro2",
@@ -207,9 +207,9 @@ mod tests {
fn generating_account_addresses() {
// test vectors produced from our js wallet
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"),
("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"),
("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")
("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", "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", "nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4")
];
for (mnemonic, address) in mnemonic_address.into_iter() {
+11
View File
@@ -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"),
}
}
+19 -14
View File
@@ -6,6 +6,15 @@ use time::OffsetDateTime;
use url::Url;
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)]
pub struct ValidatorDetails {
@@ -38,6 +47,7 @@ impl ValidatorDetails {
}
}
#[cfg(network = "milhon")]
pub fn default_validators() -> Vec<ValidatorDetails> {
vec![
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> {
default_validators()
.iter()
@@ -62,10 +80,7 @@ pub fn default_api_endpoints() -> Vec<Url> {
.collect()
}
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen";
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
// Ethereum constants used for token bridge
/// How much bandwidth (in bytes) one token can buy
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
/// 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
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 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
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
// (note that the 'amount' postfix is relevant here as the full gas price also includes denom)
pub const GAS_PRICE_AMOUNT: f64 = 0.025;
+17
View File
@@ -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";
+17
View File
@@ -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";
+1 -2
View File
@@ -282,8 +282,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
}
#[entry_point]
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)]
+2 -2
View File
@@ -16,8 +16,8 @@ serde_json = "1.0.66"
tokio = {version = "1.9.0", features = ["full"] }
chrono = { version = "0.4.19", features = ["serde"] }
schemars = { version = "0.8", features = ["preserve_order"] }
okapi = { version = "0.6.0-alpha-1", features = ["derive_json_schema"] }
rocket_okapi = "0.7.0-alpha-1"
okapi = { version = "0.7.0-rc.1", features = ["impl_json_schema"] }
rocket_okapi = { version = "0.8.0-rc.1", features = ["swagger"] }
log = "0.4.0"
pretty_env_logger = "0.4.0"
thiserror = "1.0.29"
@@ -15,6 +15,13 @@ impl GeoLocateTask {
}
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...");
tokio::spawn(async move {
let mut interval_timer = tokio::time::interval(std::time::Duration::from_millis(50));
+5 -2
View File
@@ -2,9 +2,12 @@ use crate::country_statistics::country_nodes_distribution::CountryNodesDistribut
use crate::state::ExplorerApiStateContext;
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;
pub fn country_statistics_make_default_routes() -> Vec<Route> {
routes_with_openapi![index]
pub fn country_statistics_make_default_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![settings: index]
}
// We could either separate stuff by structure (like this, http is separate), or we could just
+38 -27
View File
@@ -1,12 +1,13 @@
use log::info;
use rocket::http::Method;
use rocket::Request;
use rocket::{Build, Request, Rocket};
use rocket_cors::{AllowedHeaders, AllowedOrigins};
use rocket_okapi::swagger_ui::make_swagger_ui;
use crate::country_statistics::http::country_statistics_make_default_routes;
use crate::http::swagger::get_docs;
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::state::ExplorerApiStateContext;
@@ -15,35 +16,45 @@ mod swagger;
pub(crate) fn start(state: ExplorerApiStateContext) {
tokio::spawn(async move {
info!("Starting up...");
let allowed_origins = AllowedOrigins::all();
// You can also deserialize this
let cors = rocket_cors::CorsOptions {
allowed_origins,
allowed_methods: vec![Method::Get].into_iter().map(From::from).collect(),
allowed_headers: AllowedHeaders::some(&["*"]),
allow_credentials: true,
..Default::default()
}
.to_cors()
.unwrap();
let config = rocket::config::Config::release_default();
rocket::build()
.configure(config)
.mount("/countries", country_statistics_make_default_routes())
.mount("/ping", ping_make_default_routes())
.mount("/mix-node", mix_node_make_default_routes())
.mount("/swagger", make_swagger_ui(&get_docs()))
.register("/", catchers![not_found])
.manage(state)
.attach(cors)
.launch()
.await
configure_rocket(state).launch().await
});
}
fn configure_rocket(state: ExplorerApiStateContext) -> Rocket<Build> {
let allowed_origins = AllowedOrigins::all();
// You can also deserialize this
let cors = rocket_cors::CorsOptions {
allowed_origins,
allowed_methods: vec![Method::Get].into_iter().map(From::from).collect(),
allowed_headers: AllowedHeaders::some(&["*"]),
allow_credentials: true,
..Default::default()
}
.to_cors()
.unwrap();
let openapi_settings = rocket_okapi::settings::OpenApiSettings::default();
let config = rocket::config::Config::release_default();
let mut building_rocket = rocket::build().configure(config);
mount_endpoints_and_merged_docs! {
building_rocket,
"/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()))
.register("/", catchers![not_found])
.manage(state)
.attach(cors)
}
#[catch(404)]
pub(crate) fn not_found(req: &Request) -> String {
format!("I couldn't find '{}'. Try something else?", req.uri())
+2 -6
View File
@@ -1,12 +1,8 @@
use rocket_okapi::swagger_ui::{SwaggerUIConfig, UrlObject};
use rocket_okapi::swagger_ui::SwaggerUIConfig;
pub(crate) fn get_docs() -> SwaggerUIConfig {
SwaggerUIConfig {
urls: vec![
UrlObject::new("Country statistics", "/countries/openapi.json"),
UrlObject::new("Node ping", "/ping/openapi.json"),
UrlObject::new("Mix node", "/mix-node/openapi.json"),
],
url: "../v1/openapi.json".to_owned(),
..Default::default()
}
}
+5
View File
@@ -35,6 +35,11 @@ impl ExplorerApi {
async fn run(&mut self) {
info!("Explorer API starting up...");
info!(
"Using validator API - {}",
network_defaults::default_api_endpoints()[0].clone()
);
// spawn concurrent tasks
mix_nodes::tasks::MixNodesTasks::new(self.state.clone()).start();
country_statistics::distribution::CountryStatisticsDistributionTask::new(
+6 -12
View File
@@ -1,6 +1,9 @@
use reqwest::Error as ReqwestError;
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 serde::Serialize;
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::state::ExplorerApiStateContext;
pub fn mix_node_make_default_routes() -> Vec<Route> {
routes_with_openapi![
get_delegations,
pub fn mix_node_make_default_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![
settings: get_delegations,
get_all_delegations,
get_description,
get_stats,
list
]
}
@@ -29,14 +31,6 @@ pub(crate) struct PrettyMixNodeBondWithLocation {
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")]
#[get("/<pubkey>/delegations")]
pub(crate) async fn get_delegations(pubkey: &str) -> Json<Vec<Delegation>> {
+20
View File
@@ -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
View File
@@ -1,3 +1,4 @@
pub(crate) mod http;
pub(crate) mod tasks;
mod utils;
+5 -2
View File
@@ -4,6 +4,9 @@ use std::time::Duration;
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 mixnet_contract::MixNodeBond;
@@ -12,8 +15,8 @@ use crate::state::ExplorerApiStateContext;
const CONNECTION_TIMEOUT_SECONDS: Duration = Duration::from_secs(10);
pub fn ping_make_default_routes() -> Vec<Route> {
routes_with_openapi![index]
pub fn ping_make_default_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![settings: index]
}
#[openapi(tag = "ping")]
-3
View File
@@ -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
View File
@@ -1,3 +1,5 @@
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
EXPLORER_API_URL=https://sandbox-explorer.nymtech.net/api/v1
VALIDATOR_API_URL=https://sandbox-validator.nymtech.net
BIG_DIPPER_URL=https://sandbox-blocks.nymtech.net
CURRENCY_DENOM=unymt
CURRENCY_STAKING_DENOM=unyxt
+10 -9
View File
@@ -1,16 +1,17 @@
// master APIs
export const MASTER_URL = process.env.EXPLORER_API_URL;
export const MASTER_VALIDATOR_URL = process.env.VALIDATOR_API_URL;
export const API_BASE_URL = process.env.EXPLORER_API_URL;
export const VALIDATOR_API_BASE_URL = process.env.VALIDATOR_API_URL;
export const BIG_DIPPER = process.env.BIG_DIPPER_URL;
// specific API routes
export const MIXNODE_PING = `${MASTER_URL}/api/ping`;
export const MIXNODES_API = `${MASTER_URL}/api/mix-node`;
export const GATEWAYS_API = `${MASTER_VALIDATOR_URL}/api/v1/gateways`;
export const VALIDATORS_API = `${MASTER_VALIDATOR_URL}/validators`;
export const BLOCK_API = `${MASTER_VALIDATOR_URL}/block`;
export const COUNTRY_DATA_API = `${MASTER_URL}/api/countries`;
export const UPTIME_STORY_API = `${MASTER_VALIDATOR_URL}/api/v1/status/mixnode`; // add ID then '/history' to this.
export const MIXNODE_PING = `${API_BASE_URL}/ping`;
export const MIXNODES_API = `${API_BASE_URL}/mix-nodes`;
export const MIXNODE_API = `${API_BASE_URL}/mix-node`;
export const GATEWAYS_API = `${VALIDATOR_API_BASE_URL}/api/v1/gateways`;
export const VALIDATORS_API = `${VALIDATOR_API_BASE_URL}/validators`;
export const BLOCK_API = `${VALIDATOR_API_BASE_URL}/block`;
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
export const MIXNODE_API_ERROR =
+3 -2
View File
@@ -6,6 +6,7 @@ import {
COUNTRY_DATA_API,
MIXNODE_PING,
UPTIME_STORY_API,
MIXNODE_API,
} from './constants';
import {
@@ -87,10 +88,10 @@ export class Api {
static fetchDelegationsById = async (
id: string,
): Promise<DelegationsResponse> =>
(await fetch(`${MIXNODES_API}/${id}/delegations`)).json();
(await fetch(`${MIXNODE_API}/${id}/delegations`)).json();
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> =>
(await fetch(`${MIXNODE_PING}/${id}`)).json();
+16 -17
View File
@@ -1,6 +1,5 @@
import * as React from 'react';
import { printableCoin } from '@nymproject/nym-validator-client';
import { Alert, CircularProgress, useMediaQuery, Box } from '@mui/material';
import { Alert, Box, CircularProgress, useMediaQuery } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
@@ -11,6 +10,7 @@ import TableRow from '@mui/material/TableRow';
import Paper from '@mui/material/Paper';
import { useMainContext } from 'src/context/main';
import { ExpandMore } from '@mui/icons-material';
import { currencyToString } from '../utils/currency';
export const BondBreakdownTable: React.FC = () => {
const { mixnodeDetailInfo, delegations } = useMainContext();
@@ -34,24 +34,23 @@ export const BondBreakdownTable: React.FC = () => {
const thisMixnode = mixnodeDetailInfo?.data[0];
// delegations
const decimalisedDelegations = printableCoin({
amount: thisMixnode.total_delegation.amount.toString(),
denom: thisMixnode.total_delegation.denom,
});
const decimalisedDelegations = currencyToString(
thisMixnode.total_delegation.amount.toString(),
thisMixnode.total_delegation.denom,
);
// pledges
const decimalisedPledges = printableCoin({
amount: thisMixnode.bond_amount.amount.toString(),
denom: thisMixnode.bond_amount.denom,
});
const decimalisedPledges = currencyToString(
thisMixnode.pledge_amount.amount.toString(),
thisMixnode.pledge_amount.denom,
);
// 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 bondsTotal = printableCoin({
amount: (delegationsSum + pledgesSum).toString(),
denom: 'upunk',
});
const bondsTotal = currencyToString(
(delegationsSum + pledgesSum).toString(),
);
setBonds({
delegations: decimalisedDelegations,
@@ -89,7 +88,7 @@ export const BondBreakdownTable: React.FC = () => {
mixnodeDetailInfo.data[0].total_delegation.amount,
);
const rawPledgeAmount = Number(
mixnodeDetailInfo.data[0].bond_amount.amount,
mixnodeDetailInfo.data[0].pledge_amount.amount,
);
const rawTotalBondsAmount = rawDelegationAmount + rawPledgeAmount;
return ((num * 100) / rawTotalBondsAmount).toFixed(1);
@@ -203,7 +202,7 @@ export const BondBreakdownTable: React.FC = () => {
{owner}
</TableCell>
<TableCell align="left">
{printableCoin({ amount: amount.toString(), denom })}
{currencyToString(amount.toString(), denom)}
</TableCell>
<TableCell align="left">
{calcBondPercentage(amount)}%
+2 -2
View File
@@ -8,9 +8,9 @@ import {
TableHead,
TableRow,
} from '@mui/material';
import { printableCoin } from '@nymproject/nym-validator-client';
import { cellStyles } from './Universal-DataGrid';
import { MixnodeRowType } from '../utils/index';
import { currencyToString } from '../utils/currency';
export type ColumnsType = {
field: string;
@@ -28,7 +28,7 @@ export interface UniversalTableProps {
function formatCellValues(val: string | number, field: string) {
if (field === 'bond') {
return printableCoin({ amount: val.toString(), denom: 'upunk' });
return currencyToString(val.toString());
}
return val;
}
+6 -12
View File
@@ -1,7 +1,6 @@
import * as React from 'react';
import { Button, Card, Grid, Typography } from '@mui/material';
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
import { printableCoin } from '@nymproject/nym-validator-client';
import { SelectChangeEvent } from '@mui/material/Select';
import { useMainContext } from 'src/context/main';
import { gatewayToGridRow } from 'src/utils';
@@ -13,6 +12,7 @@ import {
cellStyles,
UniversalDataGrid,
} from 'src/components/Universal-DataGrid';
import { currencyToString } from '../../utils/currency';
export const PageGateways: React.FC = () => {
const { gateways } = useMainContext();
@@ -79,17 +79,11 @@ export const PageGateways: React.FC = () => {
renderHeader: () => <CustomColumnHeading headingTitle="Pledge" />,
headerClassName: 'MuiDataGrid-header-override',
headerAlign: 'left',
renderCell: (params: GridRenderCellParams) => {
const bondAsPunk = printableCoin({
amount: params.value as string,
denom: 'upunk',
});
return (
<Typography sx={cellStyles} data-testid="pledge-amount">
{bondAsPunk}
</Typography>
);
},
renderCell: (params: GridRenderCellParams) => (
<Typography sx={cellStyles} data-testid="pledge-amount">
{currencyToString(params.value)}
</Typography>
),
},
{
field: 'host',
+10 -16
View File
@@ -1,6 +1,5 @@
import * as React from 'react';
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 { Link as RRDLink } from 'react-router-dom';
import { SelectChangeEvent } from '@mui/material/Select';
@@ -15,6 +14,7 @@ import {
UniversalDataGrid,
cellStyles,
} from 'src/components/Universal-DataGrid';
import { currencyToString } from '../../utils/currency';
export const PageMixnodes: React.FC = () => {
const { mixnodes } = useMainContext();
@@ -92,21 +92,15 @@ export const PageMixnodes: React.FC = () => {
headerClassName: 'MuiDataGrid-header-override',
width: 150,
headerAlign: 'left',
renderCell: (params: GridRenderCellParams) => {
const bondAsPunk = printableCoin({
amount: params.value as string,
denom: 'upunk',
});
return (
<MuiLink
sx={cellStyles}
component={RRDLink}
to={`/network-components/mixnodes/${params.row.identity_key}`}
>
{bondAsPunk}
</MuiLink>
);
},
renderCell: (params: GridRenderCellParams) => (
<MuiLink
sx={cellStyles}
component={RRDLink}
to={`/network-components/mixnodes/${params.row.identity_key}`}
>
{currencyToString(params.value)}
</MuiLink>
),
},
{
field: 'location',
+7 -6
View File
@@ -7,13 +7,14 @@ export interface ClientConfig {
export interface MixNode {
host: string;
location: string;
mix_port: number;
http_api_port: number;
verloc_port: number;
sphinx_key: string;
identity_key: string;
version: string;
mix_port: number;
verloc_port: number;
http_api_port: number;
profit_margin_percent: number;
location: string;
}
export interface Gateway {
@@ -32,7 +33,7 @@ export interface Amount {
}
export interface MixNodeResponseItem {
bond_amount: Amount;
pledge_amount: Amount;
total_delegation: Amount;
owner: string;
layer: string;
@@ -74,7 +75,7 @@ export type MixNodeHistoryResponse = StatsResponse;
export interface GatewayResponseItem {
block_height: number;
bond_amount: Amount;
pledge_amount: Amount;
total_delegation: Amount;
owner: string;
gateway: Gateway;
+19
View File
@@ -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,
});
+2 -2
View File
@@ -69,7 +69,7 @@ export function mixnodeToGridRow(arrayOfMixnodes: MixNodeResponse): any {
return !arrayOfMixnodes
? []
: 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 totalBond = pledge + delegations;
const selfPercentage = ((pledge * 100) / totalBond).toFixed(2);
@@ -96,7 +96,7 @@ export function gatewayToGridRow(
owner: gw.owner,
identity_key: gw.gateway.identity_key || '',
location: gw?.gateway?.location || '',
bond: gw.bond_amount.amount || 0,
bond: gw.pledge_amount.amount || 0,
host: gw.gateway.host || '',
}));
}