Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e587d20a65 | |||
| 56846fee77 | |||
| 52949f825a | |||
| 2705330595 |
+8
-2
@@ -7,12 +7,12 @@ use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::AccountId;
|
||||
use nym_mixnet_contract_common::NodeId;
|
||||
use serde::Deserialize;
|
||||
|
||||
use nym_mixnet_contract_common::NodeId;
|
||||
pub use nym_node_families_contract_common::{
|
||||
msg::QueryMsg as NodeFamiliesQueryMsg, AllFamilyMembersPagedResponse,
|
||||
AllPastFamilyInvitationsPagedResponse, FamiliesPagedResponse, FamilyMemberRecord,
|
||||
AllPastFamilyInvitationsPagedResponse, Config, FamiliesPagedResponse, FamilyMemberRecord,
|
||||
FamilyMembersPagedResponse, GlobalPastFamilyInvitationCursor, NodeFamily,
|
||||
NodeFamilyByNameResponse, NodeFamilyByOwnerResponse, NodeFamilyId,
|
||||
NodeFamilyMembershipResponse, NodeFamilyResponse, PastFamilyInvitation,
|
||||
@@ -35,6 +35,11 @@ pub trait NodeFamiliesQueryClient {
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn get_config(&self) -> Result<Config, NyxdError> {
|
||||
self.query_node_families_contract(NodeFamiliesQueryMsg::GetConfig {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_family_by_id(
|
||||
&self,
|
||||
family_id: NodeFamilyId,
|
||||
@@ -360,6 +365,7 @@ mod tests {
|
||||
msg: NodeFamiliesQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
NodeFamiliesQueryMsg::GetConfig {} => client.get_config().ignore(),
|
||||
NodeFamiliesQueryMsg::GetFamilyById { family_id } => {
|
||||
client.get_family_by_id(family_id).ignore()
|
||||
}
|
||||
|
||||
@@ -96,6 +96,10 @@ pub enum ExecuteMsg {
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "schema", derive(cosmwasm_schema::QueryResponses))]
|
||||
pub enum QueryMsg {
|
||||
/// Retrieve current contract configuration values
|
||||
#[cfg_attr(feature = "schema", returns(Config))]
|
||||
GetConfig {},
|
||||
|
||||
/// Look up a single family by its id.
|
||||
#[cfg_attr(feature = "schema", returns(NodeFamilyResponse))]
|
||||
GetFamilyById { family_id: NodeFamilyId },
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::{Any, MessageRegistry, ParsedTransactionDetails, default_message_regi
|
||||
use futures::StreamExt;
|
||||
use futures::future::join3;
|
||||
use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
use tendermint::{Block, Hash};
|
||||
use tendermint_rpc::endpoint::{block, block_results, tx, validators};
|
||||
@@ -18,6 +19,38 @@ use tokio::sync::Mutex;
|
||||
use tracing::{debug, instrument, warn};
|
||||
use url::Url;
|
||||
|
||||
const MAX_QUERY_ATTEMPTS: usize = 3;
|
||||
|
||||
/// Runs `op` up to `max_attempts` times (at least once), returning the first success or, on full
|
||||
/// exhaustion, the last error encountered.
|
||||
async fn query_with_retries<F, Fut, T>(mut max_attempts: usize, op: F) -> Result<T, ScraperError>
|
||||
where
|
||||
F: Fn() -> Fut,
|
||||
Fut: Future<Output = Result<T, ScraperError>>,
|
||||
{
|
||||
if max_attempts == 0 {
|
||||
max_attempts = 1;
|
||||
}
|
||||
|
||||
let mut last_err = None;
|
||||
|
||||
for i in 0..max_attempts {
|
||||
match op().await {
|
||||
Ok(result) => return Ok(result),
|
||||
Err(err) => {
|
||||
debug!("query failed, retrying {}/{max_attempts} - {err}", i + 1);
|
||||
last_err = Some(err);
|
||||
}
|
||||
}
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_millis(300 * (i as u64 + 1))).await;
|
||||
}
|
||||
|
||||
// SAFETY: max_attempts >= 1, so we only reach here after at least one recorded failure
|
||||
#[allow(clippy::unwrap_used)]
|
||||
Err(last_err.unwrap())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RetrievalConfig {
|
||||
pub get_validators: bool,
|
||||
@@ -173,13 +206,24 @@ impl RpcClient {
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self), err(Display))]
|
||||
async fn get_block_results_with_retries(
|
||||
&self,
|
||||
height: u32,
|
||||
max_attempts: usize,
|
||||
) -> Result<block_results::Response, ScraperError> {
|
||||
query_with_retries(max_attempts, || self.get_block_results(height)).await
|
||||
}
|
||||
|
||||
async fn maybe_get_block_results(
|
||||
&self,
|
||||
height: u32,
|
||||
retrieve: bool,
|
||||
) -> Result<Option<block_results::Response>, ScraperError> {
|
||||
if retrieve {
|
||||
self.get_block_results(height).await.map(Some)
|
||||
self.get_block_results_with_retries(height, MAX_QUERY_ATTEMPTS)
|
||||
.await
|
||||
.map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -219,8 +263,6 @@ impl RpcClient {
|
||||
|
||||
// "Data is just a wrapper for a list of transactions, where transactions are arbitrary byte arrays"
|
||||
// source: https://github.com/tendermint/spec/blob/d46cd7f573a2c6a2399fcab2cde981330aa63f37/spec/core/data_structures.md#data
|
||||
//
|
||||
// I hate that zip as much as you, dear reader, but for some reason the compiler didn't let me remove the `move`
|
||||
futures::stream::iter(
|
||||
raw.iter()
|
||||
.map(tx_hash)
|
||||
@@ -228,12 +270,14 @@ impl RpcClient {
|
||||
.zip(std::iter::repeat(ordered_results.clone())),
|
||||
)
|
||||
.for_each_concurrent(4, |((id, tx_hash), ordered_results)| async move {
|
||||
let res = self.get_transaction_result(tx_hash).await;
|
||||
let res = self
|
||||
.get_transaction_result_with_retries(tx_hash, MAX_QUERY_ATTEMPTS)
|
||||
.await;
|
||||
ordered_results.lock().await.insert(id, res);
|
||||
})
|
||||
.await;
|
||||
|
||||
// safety the futures have completed so we MUST have the only arc reference
|
||||
// safety: the futures have completed so we MUST have the only arc reference
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let inner = Arc::into_inner(ordered_results).unwrap().into_inner();
|
||||
|
||||
@@ -266,6 +310,15 @@ impl RpcClient {
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self, tx_hash), fields(tx_hash = %tx_hash), err(Display))]
|
||||
async fn get_transaction_result_with_retries(
|
||||
&self,
|
||||
tx_hash: Hash,
|
||||
max_attempts: usize,
|
||||
) -> Result<tx::Response, ScraperError> {
|
||||
query_with_retries(max_attempts, || self.get_transaction_result(tx_hash)).await
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn get_validators_details(
|
||||
&self,
|
||||
@@ -282,13 +335,24 @@ impl RpcClient {
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self), err(Display))]
|
||||
async fn get_validators_details_with_retries(
|
||||
&self,
|
||||
height: u32,
|
||||
max_attempts: usize,
|
||||
) -> Result<validators::Response, ScraperError> {
|
||||
query_with_retries(max_attempts, || self.get_validators_details(height)).await
|
||||
}
|
||||
|
||||
async fn maybe_get_validators_details(
|
||||
&self,
|
||||
height: u32,
|
||||
retrieve: bool,
|
||||
) -> Result<Option<validators::Response>, ScraperError> {
|
||||
if retrieve {
|
||||
self.get_validators_details(height).await.map(Some)
|
||||
self.get_validators_details_with_retries(height, MAX_QUERY_ATTEMPTS)
|
||||
.await
|
||||
.map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
Generated
+1
-2
@@ -1037,7 +1037,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "node-families"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cosmwasm-schema",
|
||||
@@ -1052,7 +1052,6 @@ dependencies = [
|
||||
"nym-mixnet-contract",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-node-families-contract-common",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -87,7 +87,7 @@ cw3-flex-multisig = { version = "2.0.0", path = "multisig/cw3-flex-multisig" }
|
||||
cw4-group = { version = "2.0.0", path = "multisig/cw4-group" }
|
||||
nym-mixnet-contract = { version = "1.5.1", path = "mixnet" }
|
||||
nym-vesting-contract = { version = "1.4.1", path = "vesting" }
|
||||
node-families = { version = "0.1.0", path = "node-families" }
|
||||
node-families = { version = "0.1.1", path = "node-families" }
|
||||
|
||||
[workspace.lints.clippy]
|
||||
unwrap_used = "deny"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "node-families"
|
||||
description = "Nym Node Families contract"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
@@ -25,7 +25,6 @@ cosmwasm-std = { workspace = true }
|
||||
cw2 = { workspace = true }
|
||||
cw-storage-plus = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
cosmwasm-schema = { workspace = true, optional = true }
|
||||
cw-utils = { workspace = true }
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
use crate::queries::{
|
||||
query_all_family_members_paged, query_all_past_invitations_paged,
|
||||
query_all_pending_invitations_paged, query_families_paged, query_family_by_id,
|
||||
query_all_pending_invitations_paged, query_config, query_families_paged, query_family_by_id,
|
||||
query_family_by_name, query_family_by_owner, query_family_members_paged,
|
||||
query_family_membership, query_past_invitations_for_family_paged,
|
||||
query_past_invitations_for_node_paged, query_past_members_for_family_paged,
|
||||
@@ -100,6 +100,7 @@ pub fn execute(
|
||||
#[entry_point]
|
||||
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<Binary, NodeFamiliesContractError> {
|
||||
match msg {
|
||||
QueryMsg::GetConfig {} => Ok(to_json_binary(&query_config(deps)?)?),
|
||||
QueryMsg::GetFamilyById { family_id } => {
|
||||
Ok(to_json_binary(&query_family_by_id(deps, family_id)?)?)
|
||||
}
|
||||
|
||||
@@ -7,18 +7,23 @@ use cosmwasm_std::{Deps, Env, Order, StdResult};
|
||||
use cw_storage_plus::Bound;
|
||||
use nym_mixnet_contract_common::NodeId;
|
||||
use nym_node_families_contract_common::{
|
||||
AllFamilyMembersPagedResponse, AllPastFamilyInvitationsPagedResponse, FamiliesPagedResponse,
|
||||
FamilyMemberRecord, FamilyMembersPagedResponse, GlobalPastFamilyInvitationCursor,
|
||||
NodeFamiliesContractError, NodeFamilyByNameResponse, NodeFamilyByOwnerResponse, NodeFamilyId,
|
||||
NodeFamilyMembershipResponse, NodeFamilyResponse, PastFamilyInvitationCursor,
|
||||
PastFamilyInvitationForNodeCursor, PastFamilyInvitationsForNodePagedResponse,
|
||||
PastFamilyInvitationsPagedResponse, PastFamilyMemberCursor, PastFamilyMemberForNodeCursor,
|
||||
PastFamilyMembersForNodePagedResponse, PastFamilyMembersPagedResponse,
|
||||
PendingFamilyInvitationDetails, PendingFamilyInvitationResponse,
|
||||
PendingFamilyInvitationsPagedResponse, PendingInvitationsForNodePagedResponse,
|
||||
PendingInvitationsPagedResponse,
|
||||
AllFamilyMembersPagedResponse, AllPastFamilyInvitationsPagedResponse, Config,
|
||||
FamiliesPagedResponse, FamilyMemberRecord, FamilyMembersPagedResponse,
|
||||
GlobalPastFamilyInvitationCursor, NodeFamiliesContractError, NodeFamilyByNameResponse,
|
||||
NodeFamilyByOwnerResponse, NodeFamilyId, NodeFamilyMembershipResponse, NodeFamilyResponse,
|
||||
PastFamilyInvitationCursor, PastFamilyInvitationForNodeCursor,
|
||||
PastFamilyInvitationsForNodePagedResponse, PastFamilyInvitationsPagedResponse,
|
||||
PastFamilyMemberCursor, PastFamilyMemberForNodeCursor, PastFamilyMembersForNodePagedResponse,
|
||||
PastFamilyMembersPagedResponse, PendingFamilyInvitationDetails,
|
||||
PendingFamilyInvitationResponse, PendingFamilyInvitationsPagedResponse,
|
||||
PendingInvitationsForNodePagedResponse, PendingInvitationsPagedResponse,
|
||||
};
|
||||
|
||||
/// Retrieve current contract configuration values
|
||||
pub fn query_config(deps: Deps) -> Result<Config, NodeFamiliesContractError> {
|
||||
Ok(NodeFamiliesStorage::new().config.load(deps.storage)?)
|
||||
}
|
||||
|
||||
/// Resolve a single family by its id. Returns `family: None` if no family
|
||||
/// with that id exists.
|
||||
pub fn query_family_by_id(
|
||||
|
||||
Generated
+51
-36
@@ -379,8 +379,8 @@ catalogs:
|
||||
specifier: ^27.1.0
|
||||
version: 27.5.1
|
||||
joi:
|
||||
specifier: ^17.11.0
|
||||
version: 17.13.3
|
||||
specifier: ^18.2.1
|
||||
version: 18.2.1
|
||||
localforage:
|
||||
specifier: ^1.10.0
|
||||
version: 1.10.0
|
||||
@@ -939,7 +939,7 @@ importers:
|
||||
version: 2.0.3
|
||||
joi:
|
||||
specifier: 'catalog:'
|
||||
version: 17.13.3
|
||||
version: 18.2.1
|
||||
localforage:
|
||||
specifier: 'catalog:'
|
||||
version: 1.10.0
|
||||
@@ -3135,11 +3135,25 @@ packages:
|
||||
'@gar/promisify@1.1.3':
|
||||
resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
|
||||
|
||||
'@hapi/hoek@9.3.0':
|
||||
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
|
||||
'@hapi/address@5.1.1':
|
||||
resolution: {integrity: sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
'@hapi/topo@5.1.0':
|
||||
resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
|
||||
'@hapi/formula@3.0.2':
|
||||
resolution: {integrity: sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==}
|
||||
|
||||
'@hapi/hoek@11.0.7':
|
||||
resolution: {integrity: sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==}
|
||||
|
||||
'@hapi/pinpoint@2.0.1':
|
||||
resolution: {integrity: sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==}
|
||||
|
||||
'@hapi/tlds@1.1.7':
|
||||
resolution: {integrity: sha512-MgNjRwy9Ti92yVAixLmDc8dd1bJIKwO9qlWCfFQRwRmUEDPQHYn4G6hwPFvFGUTzAa0FsS+inMjLin7GnyBRhA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
'@hapi/topo@6.0.2':
|
||||
resolution: {integrity: sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==}
|
||||
|
||||
'@hookform/resolvers@2.9.11':
|
||||
resolution: {integrity: sha512-bA3aZ79UgcHj7tFV7RlgThzwSSHZgvfbt2wprldRkYBcMopdMvHyO17Wwp/twcJasNFischFfS7oz8Katz8DdQ==}
|
||||
@@ -4298,15 +4312,6 @@ packages:
|
||||
'@scure/starknet@1.1.0':
|
||||
resolution: {integrity: sha512-83g3M6Ix2qRsPN4wqLDqiRZ2GBNbjVWfboJE/9UjfG+MHr6oDSu/CWgy8hsBSJejr09DkkL+l0Ze4KVrlCIdtQ==}
|
||||
|
||||
'@sideway/address@4.1.5':
|
||||
resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
|
||||
|
||||
'@sideway/formula@3.0.1':
|
||||
resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
|
||||
|
||||
'@sideway/pinpoint@2.0.0':
|
||||
resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
|
||||
|
||||
'@sigstore/bundle@1.1.0':
|
||||
resolution: {integrity: sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
@@ -4338,6 +4343,9 @@ packages:
|
||||
'@sinonjs/fake-timers@8.1.0':
|
||||
resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==}
|
||||
|
||||
'@standard-schema/spec@1.1.0':
|
||||
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
|
||||
|
||||
'@starknet-io/types-js@0.8.4':
|
||||
resolution: {integrity: sha512-0RZ3TZHcLsUTQaq1JhDSCM8chnzO4/XNsSCozwDET64JK5bjFDIf2ZUkta+tl5Nlbf4usoU7uZiDI/Q57kt2SQ==}
|
||||
|
||||
@@ -9673,8 +9681,9 @@ packages:
|
||||
node-notifier:
|
||||
optional: true
|
||||
|
||||
joi@17.13.3:
|
||||
resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
|
||||
joi@18.2.1:
|
||||
resolution: {integrity: sha512-2/OKlogiESf2Nh3TFCrRjrr9z1DRHeW0I+KReF67+4J0Ns+8hBtHRmoWAZ2OFU6I5+TWLEe6sVlSdXPjHm5UbQ==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
js-sha3@0.8.0:
|
||||
resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==}
|
||||
@@ -15873,11 +15882,21 @@ snapshots:
|
||||
|
||||
'@gar/promisify@1.1.3': {}
|
||||
|
||||
'@hapi/hoek@9.3.0': {}
|
||||
|
||||
'@hapi/topo@5.1.0':
|
||||
'@hapi/address@5.1.1':
|
||||
dependencies:
|
||||
'@hapi/hoek': 9.3.0
|
||||
'@hapi/hoek': 11.0.7
|
||||
|
||||
'@hapi/formula@3.0.2': {}
|
||||
|
||||
'@hapi/hoek@11.0.7': {}
|
||||
|
||||
'@hapi/pinpoint@2.0.1': {}
|
||||
|
||||
'@hapi/tlds@1.1.7': {}
|
||||
|
||||
'@hapi/topo@6.0.2':
|
||||
dependencies:
|
||||
'@hapi/hoek': 11.0.7
|
||||
|
||||
'@hookform/resolvers@2.9.11(react-hook-form@7.75.0(react@19.2.6))':
|
||||
dependencies:
|
||||
@@ -17424,14 +17443,6 @@ snapshots:
|
||||
'@noble/curves': 1.7.0
|
||||
'@noble/hashes': 1.6.1
|
||||
|
||||
'@sideway/address@4.1.5':
|
||||
dependencies:
|
||||
'@hapi/hoek': 9.3.0
|
||||
|
||||
'@sideway/formula@3.0.1': {}
|
||||
|
||||
'@sideway/pinpoint@2.0.0': {}
|
||||
|
||||
'@sigstore/bundle@1.1.0':
|
||||
dependencies:
|
||||
'@sigstore/protobuf-specs': 0.2.1
|
||||
@@ -17471,6 +17482,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@sinonjs/commons': 1.8.6
|
||||
|
||||
'@standard-schema/spec@1.1.0': {}
|
||||
|
||||
'@starknet-io/types-js@0.8.4': {}
|
||||
|
||||
'@starknet-io/types-js@0.9.2': {}
|
||||
@@ -25301,13 +25314,15 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
joi@17.13.3:
|
||||
joi@18.2.1:
|
||||
dependencies:
|
||||
'@hapi/hoek': 9.3.0
|
||||
'@hapi/topo': 5.1.0
|
||||
'@sideway/address': 4.1.5
|
||||
'@sideway/formula': 3.0.1
|
||||
'@sideway/pinpoint': 2.0.0
|
||||
'@hapi/address': 5.1.1
|
||||
'@hapi/formula': 3.0.2
|
||||
'@hapi/hoek': 11.0.7
|
||||
'@hapi/pinpoint': 2.0.1
|
||||
'@hapi/tlds': 1.1.7
|
||||
'@hapi/topo': 6.0.2
|
||||
'@standard-schema/spec': 1.1.0
|
||||
|
||||
js-sha3@0.8.0: {}
|
||||
|
||||
|
||||
+1
-1
@@ -230,7 +230,7 @@ catalog:
|
||||
"flat": "^5.0.2"
|
||||
"glob": "^10.5.0"
|
||||
"hex-rgb": "^4.3.0"
|
||||
"joi": "^17.11.0"
|
||||
"joi": "^18.2.1"
|
||||
"localforage": "^1.10.0"
|
||||
"lodash": "^4.17.21"
|
||||
"lodash.padend": "^4.6.1"
|
||||
|
||||
@@ -95,7 +95,7 @@ a:hover {
|
||||
You are most likely accessing this website because you've had some issue with
|
||||
the traffic coming from this IP. This router is part of the <a
|
||||
href="https://nym.com/">NYM project</a>, which is
|
||||
dedicated to <a href="https://nym.com/about/mission">create</a> outstanding
|
||||
dedicated to <a href="https://nym.com/features">create</a> outstanding
|
||||
privacy software that is legally compliant without sacrificing integrity or
|
||||
having any backdoors.
|
||||
This router IP should be generating no other traffic, unless it has been
|
||||
@@ -168,7 +168,7 @@ a:hover {
|
||||
</svg>
|
||||
</p>
|
||||
|
||||
<p><a href="https://nym.com/about/mixnet">Read more about how Nym works.</a></p>
|
||||
<p><a href="https://nym.com/docs/network/overview">Read more about how Nym works.</a></p>
|
||||
|
||||
<p>
|
||||
Nym relies on a growing ecosystem of users, developers and researcher partners
|
||||
@@ -227,7 +227,7 @@ a:hover {
|
||||
<p style="text-align:center">
|
||||
<img
|
||||
class="logo"
|
||||
src="https://raw.githubusercontent.com/nymtech/websites/main/www/nym.com/public/images/Nym_meta_Image.png"
|
||||
src="https://raw.githubusercontent.com/nymtech/nym/develop/explorer-v2/public/images/Network.webp"
|
||||
alt=""
|
||||
style="max-width:320px;width:100%;height:auto"
|
||||
onerror="this.onerror=null;this.src='/images/nym_logo.png';"
|
||||
|
||||
Reference in New Issue
Block a user