Compare commits

...

7 Commits

Author SHA1 Message Date
benedettadavico 59feaf0c07 Merge branch 'develop' into feature/wasm-tests 2023-03-16 17:36:28 +01:00
benedettadavico f20eaa875c sdk wasm tests 2023-03-16 17:35:16 +01:00
Jon Häggblad 4c2967a733 Delete stray .gitignore file 2023-03-16 15:27:45 +00:00
Jon Häggblad 2b80e5d1c9 Remove leftover file from deleted crate 2023-03-16 12:59:46 +00:00
Jon Häggblad 4e7ff53214 Contract and client support for updating gateway config (#3166)
* mixnet-contract: add update gateway config

* mixnet-contract: tests for updating gateway config

* vesting-contract: add update gateway config

* validator-client: add update gateway config

* wallet: add update_gateway_config

* common/commands: add support for setting gateway config

* Remove commented out line

* Review fixes

* Generate ts file for GatewayConfigUpdate type

* Add generated GatewayConfigUpdate.ts file
2023-03-16 13:43:56 +01:00
Jon Häggblad 9ec36e49b7 contracts: remove .gitignore with Cargo.lock in it
While developing the service-provider-directory contract I ran into
issues with the lock file being inconsistent for cosmwasm-std (1.0 vs
1.2) and was hidden due to ignoring the lock file
2023-03-16 12:28:35 +00:00
benedettadavico 6e27497f14 sdk tests 2023-03-14 18:41:08 +01:00
37 changed files with 635 additions and 18 deletions
-3
View File
@@ -1,3 +0,0 @@
/target
**/*.rs.bk
Cargo.lock
View File
@@ -9,6 +9,7 @@ use crate::nyxd::{Fee, NyxdClient, SigningCosmWasmClient};
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::reward_params::{IntervalRewardingParamsUpdate, Performance};
use nym_mixnet_contract_common::{
@@ -498,6 +499,36 @@ pub trait MixnetSigningClient {
.await
}
async fn update_gateway_config(
&self,
new_config: GatewayConfigUpdate,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateGatewayConfig { new_config },
vec![],
)
.await
}
async fn update_gateway_config_on_behalf(
&self,
owner: AccountId,
new_config: GatewayConfigUpdate,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateGatewayConfigOnBehalf {
new_config,
owner: owner.to_string(),
},
vec![],
)
.await
}
// delegation-related:
async fn delegate_to_mixnode(
@@ -7,6 +7,7 @@ use crate::nyxd::error::NyxdError;
use crate::nyxd::{Coin, Fee, NyxdClient};
use async_trait::async_trait;
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixId, MixNode};
use nym_vesting_contract_common::messages::{
@@ -35,6 +36,12 @@ pub trait VestingSigningClient {
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError>;
async fn vesting_update_gateway_config(
&self,
new_config: GatewayConfigUpdate,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError>;
async fn update_mixnet_address(
&self,
address: &str,
@@ -185,6 +192,19 @@ impl<C: SigningCosmWasmClient + Sync + Send + Clone> VestingSigningClient for Ny
.await
}
async fn vesting_update_gateway_config(
&self,
new_config: GatewayConfigUpdate,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
fee,
VestingExecuteMsg::UpdateGatewayConfig { new_config },
vec![],
)
.await
}
async fn update_mixnet_address(
&self,
address: &str,
@@ -5,6 +5,7 @@ use clap::{Args, Subcommand};
pub mod bond_gateway;
pub mod gateway_bonding_sign_payload;
pub mod settings;
pub mod unbond_gateway;
pub mod vesting_bond_gateway;
pub mod vesting_unbond_gateway;
@@ -18,6 +19,8 @@ pub struct MixnetOperatorsGateway {
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsGatewayCommands {
/// Manage your gateway settings stored in the directory
Settings(settings::MixnetOperatorsGatewaySettings),
/// Bond to a gateway
Bond(bond_gateway::Args),
/// Unbond from a gateway
@@ -0,0 +1,22 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod update_config;
pub mod vesting_update_config;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsGatewaySettings {
#[clap(subcommand)]
pub command: MixnetOperatorsGatewaySettingsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsGatewaySettingsCommands {
/// Update gateway configuration
UpdateConfig(update_config::Args),
/// Update gateway configuration for a gateway bonded with locked tokens
VestingUpdateConfig(vesting_update_config::Args),
}
@@ -0,0 +1,60 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::GatewayConfigUpdate;
use validator_client::nyxd::traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub host: Option<String>,
#[clap(long)]
pub mix_port: Option<u16>,
#[clap(long)]
pub clients_port: Option<u16>,
#[clap(long)]
pub location: Option<String>,
#[clap(long)]
pub version: Option<String>,
}
pub async fn update_config(args: Args, client: SigningClient) {
info!("Update gateway config!");
let current_details = match client
.get_owned_gateway(client.address())
.await
.expect("failed to query the chain for gateway details")
.gateway
{
Some(details) => details,
None => {
log::warn!("this operator does not own a gateway to update");
return;
}
};
let update = GatewayConfigUpdate {
host: args.host.unwrap_or(current_details.gateway.host),
mix_port: args.mix_port.unwrap_or(current_details.gateway.mix_port),
clients_port: args
.clients_port
.unwrap_or(current_details.gateway.clients_port),
location: args.location.unwrap_or(current_details.gateway.location),
version: args.version.unwrap_or(current_details.gateway.version),
};
let res = client
.update_gateway_config(update, None)
.await
.expect("updating gateway config");
info!("gateway config updated: {:?}", res)
}
@@ -0,0 +1,61 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::GatewayConfigUpdate;
use validator_client::nyxd::traits::MixnetQueryClient;
use validator_client::nyxd::VestingSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub host: Option<String>,
#[clap(long)]
pub mix_port: Option<u16>,
#[clap(long)]
pub clients_port: Option<u16>,
#[clap(long)]
pub location: Option<String>,
#[clap(long)]
pub version: Option<String>,
}
pub async fn vesting_update_config(client: SigningClient, args: Args) {
info!("Update vesting gateway config!");
let current_details = match client
.get_owned_gateway(client.address())
.await
.expect("failed to query the chain for gateway details")
.gateway
{
Some(details) => details,
None => {
log::warn!("this operator does not own a gateway to update");
return;
}
};
let update = GatewayConfigUpdate {
host: args.host.unwrap_or(current_details.gateway.host),
mix_port: args.mix_port.unwrap_or(current_details.gateway.mix_port),
clients_port: args
.clients_port
.unwrap_or(current_details.gateway.clients_port),
location: args.location.unwrap_or(current_details.gateway.location),
version: args.version.unwrap_or(current_details.gateway.version),
};
let res = client
.vesting_update_gateway_config(update, None)
.await
.expect("updating vesting gateway config");
info!("gateway config updated: {:?}", res)
}
@@ -1,6 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::gateway::GatewayConfigUpdate;
use crate::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use crate::reward_params::{IntervalRewardParams, IntervalRewardingParamsUpdate};
use crate::rewarding::RewardDistribution;
@@ -42,6 +43,7 @@ pub enum MixnetEventType {
ReconcilePendingEvents,
PendingIntervalConfigUpdate,
IntervalConfigUpdate,
GatewayConfigUpdate,
}
impl From<MixnetEventType> for String {
@@ -86,6 +88,7 @@ impl ToString for MixnetEventType {
MixnetEventType::PendingIntervalConfigUpdate => "pending_interval_config_update",
MixnetEventType::IntervalConfigUpdate => "interval_config_update",
MixnetEventType::DelegationOnUnbonding => "delegation_on_unbonding_node",
MixnetEventType::GatewayConfigUpdate => "gateway_config_update",
};
format!("{EVENT_VERSION_PREFIX}{event_name}")
@@ -122,6 +125,7 @@ pub const OLD_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "old_rewarding_validator_a
pub const NEW_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "new_rewarding_validator_address";
pub const UPDATED_MIXNODE_CONFIG_KEY: &str = "updated_mixnode_config";
pub const UPDATED_GATEWAY_CONFIG_KEY: &str = "updated_gateway_config";
pub const UPDATED_MIXNODE_COST_PARAMS_KEY: &str = "updated_mixnode_cost_params";
// rewarding
@@ -382,6 +386,17 @@ pub fn new_mixnode_config_update_event(
.add_attribute(UPDATED_MIXNODE_CONFIG_KEY, update.to_inline_json())
}
pub fn new_gateway_config_update_event(
owner: &Addr,
proxy: &Option<Addr>,
update: &GatewayConfigUpdate,
) -> Event {
Event::new(MixnetEventType::GatewayConfigUpdate)
.add_attribute(OWNER_KEY, owner)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(UPDATED_GATEWAY_CONFIG_KEY, update.to_inline_json())
}
pub fn new_mixnode_pending_cost_params_update_event(
mix_id: MixId,
owner: &Addr,
@@ -112,6 +112,26 @@ impl Display for GatewayBond {
}
}
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/GatewayConfigUpdate.ts")
)]
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
pub struct GatewayConfigUpdate {
pub host: String,
pub mix_port: u16,
pub clients_port: u16,
pub location: String,
pub version: String,
}
impl GatewayConfigUpdate {
pub fn to_inline_json(&self) -> String {
serde_json::to_string(self).unwrap_or_else(|_| "serialisation failure".into())
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct PagedGatewayResponse {
pub nodes: Vec<GatewayBond>,
@@ -27,7 +27,8 @@ pub use delegation::{
PagedMixNodeDelegationsResponse,
};
pub use gateway::{
Gateway, GatewayBond, GatewayBondResponse, GatewayOwnershipResponse, PagedGatewayResponse,
Gateway, GatewayBond, GatewayBondResponse, GatewayConfigUpdate, GatewayOwnershipResponse,
PagedGatewayResponse,
};
pub use interval::{
CurrentIntervalResponse, EpochState, EpochStatus, Interval, NumberOfPendingEventsResponse,
@@ -3,6 +3,7 @@
use crate::delegation::OwnerProxySubKey;
use crate::error::MixnetContractError;
use crate::gateway::GatewayConfigUpdate;
use crate::helpers::IntoBaseDecimal;
use crate::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use crate::reward_params::{
@@ -199,6 +200,13 @@ pub enum ExecuteMsg {
UnbondGatewayOnBehalf {
owner: String,
},
UpdateGatewayConfig {
new_config: GatewayConfigUpdate,
},
UpdateGatewayConfigOnBehalf {
new_config: GatewayConfigUpdate,
owner: String,
},
// delegation-related:
DelegateToMixnode {
@@ -313,6 +321,10 @@ impl ExecuteMsg {
}
ExecuteMsg::UnbondGateway { .. } => "unbonding gateway".into(),
ExecuteMsg::UnbondGatewayOnBehalf { .. } => "unbonding gateway on behalf".into(),
ExecuteMsg::UpdateGatewayConfig { .. } => "updating gateway configuration".into(),
ExecuteMsg::UpdateGatewayConfigOnBehalf { .. } => {
"updating gateway configuration on behalf".into()
}
ExecuteMsg::DelegateToMixnode { mix_id } => format!("delegating to mixnode {mix_id}"),
ExecuteMsg::DelegateToMixnodeOnBehalf { mix_id, .. } => {
format!("delegating to mixnode {mix_id} on behalf")
@@ -17,6 +17,7 @@ pub const VESTING_MIXNODE_BONDING_EVENT_TYPE: &str = "vesting_mixnode_bonding";
pub const VESTING_PLEDGE_MORE_EVENT_TYPE: &str = "vesting_pledge_more";
pub const VESTING_MIXNODE_UNBONDING_EVENT_TYPE: &str = "vesting_mixnode_unbonding";
pub const VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE: &str = "vesting_update_mixnode_config";
pub const VESTING_UPDATE_GATEWAY_CONFIG_EVENT_TYPE: &str = "vesting_update_gateway_config";
pub const VESTING_UPDATE_MIXNODE_COST_PARAMS_EVENT_TYPE: &str =
"vesting_update_mixnode_cost_params";
@@ -121,6 +122,10 @@ pub fn new_vesting_update_mixnode_config_event() -> Event {
Event::new(VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE)
}
pub fn new_vesting_update_gateway_config_event() -> Event {
Event::new(VESTING_UPDATE_GATEWAY_CONFIG_EVENT_TYPE)
}
pub fn new_vesting_update_mixnode_cost_params_event() -> Event {
Event::new(VESTING_UPDATE_MIXNODE_COST_PARAMS_EVENT_TYPE)
}
@@ -1,6 +1,7 @@
use contracts_common::signing::MessageSignature;
use cosmwasm_std::{Coin, Timestamp};
use mixnet_contract_common::{
gateway::GatewayConfigUpdate,
mixnode::{MixNodeConfigUpdate, MixNodeCostParams},
Gateway, IdentityKey, MixId, MixNode,
};
@@ -140,6 +141,9 @@ pub enum ExecuteMsg {
owner: String,
amount: Coin,
},
UpdateGatewayConfig {
new_config: GatewayConfigUpdate,
},
TransferOwnership {
to_address: String,
},
@@ -179,6 +183,7 @@ impl ExecuteMsg {
ExecuteMsg::BondGateway { .. } => "VestingExecuteMsg::BondGateway",
ExecuteMsg::UnbondGateway { .. } => "VestingExecuteMsg::UnbondGateway",
ExecuteMsg::TrackUnbondGateway { .. } => "VestingExecuteMsg::TrackUnbondGateway",
ExecuteMsg::UpdateGatewayConfig { .. } => "VestingExecuteMsg::UpdateGatewayConfig",
ExecuteMsg::TransferOwnership { .. } => "VestingExecuteMsg::TransferOwnership",
ExecuteMsg::UpdateStakingAddress { .. } => "VestingExecuteMsg::UpdateStakingAddress",
ExecuteMsg::UpdateLockedPledgeCap { .. } => "VestingExecuteMsg::UpdateLockedPledgeCap",
-1
View File
@@ -1 +0,0 @@
Cargo.lock
+8
View File
@@ -318,6 +318,14 @@ pub fn execute(
ExecuteMsg::UnbondGatewayOnBehalf { owner } => {
crate::gateways::transactions::try_remove_gateway_on_behalf(deps, info, owner)
}
ExecuteMsg::UpdateGatewayConfig { new_config } => {
crate::gateways::transactions::try_update_gateway_config(deps, info, new_config)
}
ExecuteMsg::UpdateGatewayConfigOnBehalf { new_config, owner } => {
crate::gateways::transactions::try_update_gateway_config_on_behalf(
deps, info, new_config, owner,
)
}
// delegation-related:
ExecuteMsg::DelegateToMixnode { mix_id } => {
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::storage;
use cosmwasm_std::{Addr, Storage};
use mixnet_contract_common::{error::MixnetContractError, GatewayBond};
pub(crate) fn must_get_gateway_bond_by_owner(
store: &dyn Storage,
owner: &Addr,
) -> Result<GatewayBond, MixnetContractError> {
Ok(storage::gateways()
.idx
.owner
.item(store, owner.clone())?
.ok_or(MixnetContractError::NoAssociatedGatewayBond {
owner: owner.clone(),
})?
.1)
}
+1
View File
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod helpers;
pub mod queries;
pub mod signature_helpers;
pub mod storage;
+148 -2
View File
@@ -1,16 +1,20 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::helpers::must_get_gateway_bond_by_owner;
use super::storage;
use crate::gateways::signature_helpers::verify_gateway_bonding_signature;
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::signing::storage as signing_storage;
use crate::support::helpers::{
ensure_no_existing_bond, ensure_sent_by_vesting_contract, validate_pledge,
ensure_no_existing_bond, ensure_proxy_match, ensure_sent_by_vesting_contract, validate_pledge,
};
use cosmwasm_std::{wasm_execute, Addr, BankMsg, Coin, DepsMut, Env, MessageInfo, Response};
use mixnet_contract_common::error::MixnetContractError;
use mixnet_contract_common::events::{new_gateway_bonding_event, new_gateway_unbonding_event};
use mixnet_contract_common::events::{
new_gateway_bonding_event, new_gateway_config_update_event, new_gateway_unbonding_event,
};
use mixnet_contract_common::gateway::GatewayConfigUpdate;
use mixnet_contract_common::{Gateway, GatewayBond};
use nym_contracts_common::signing::MessageSignature;
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
@@ -189,6 +193,56 @@ pub(crate) fn _try_remove_gateway(
)))
}
pub(crate) fn try_update_gateway_config(
deps: DepsMut<'_>,
info: MessageInfo,
new_config: GatewayConfigUpdate,
) -> Result<Response, MixnetContractError> {
let owner = info.sender;
_try_update_gateway_config(deps, new_config, owner, None)
}
pub(crate) fn try_update_gateway_config_on_behalf(
deps: DepsMut,
info: MessageInfo,
new_config: GatewayConfigUpdate,
owner: String,
) -> Result<Response, MixnetContractError> {
ensure_sent_by_vesting_contract(&info, deps.storage)?;
let owner = deps.api.addr_validate(&owner)?;
let proxy = info.sender;
_try_update_gateway_config(deps, new_config, owner, Some(proxy))
}
pub(crate) fn _try_update_gateway_config(
deps: DepsMut,
new_config: GatewayConfigUpdate,
owner: Addr,
proxy: Option<Addr>,
) -> Result<Response, MixnetContractError> {
let existing_bond = must_get_gateway_bond_by_owner(deps.storage, &owner)?;
ensure_proxy_match(&proxy, &existing_bond.proxy)?;
let cfg_update_event = new_gateway_config_update_event(&owner, &proxy, &new_config);
let mut updated_bond = existing_bond.clone();
updated_bond.gateway.host = new_config.host;
updated_bond.gateway.mix_port = new_config.mix_port;
updated_bond.gateway.clients_port = new_config.clients_port;
updated_bond.gateway.location = new_config.location;
updated_bond.gateway.version = new_config.version;
storage::gateways().replace(
deps.storage,
existing_bond.identity(),
Some(&updated_bond),
Some(&existing_bond),
)?;
Ok(Response::new().add_event(cfg_update_event))
}
#[cfg(test)]
pub mod tests {
use super::*;
@@ -196,6 +250,7 @@ pub mod tests {
use crate::gateways::queries;
use crate::gateways::transactions::{
try_add_gateway, try_add_gateway_on_behalf, try_remove_gateway_on_behalf,
try_update_gateway_config, try_update_gateway_config_on_behalf,
};
use crate::interval::pending_events;
use crate::mixnet_contract_settings::storage::minimum_gateway_pledge;
@@ -207,6 +262,7 @@ pub mod tests {
use cosmwasm_std::{Addr, BankMsg, Response, Uint128};
use mixnet_contract_common::error::MixnetContractError;
use mixnet_contract_common::events::new_gateway_unbonding_event;
use mixnet_contract_common::gateway::GatewayConfigUpdate;
use mixnet_contract_common::ExecuteMsg;
#[test]
@@ -485,4 +541,94 @@ pub mod tests {
}
)
}
#[test]
fn update_gateway_config() {
let mut test = TestSetup::new();
let owner = "alice";
let info = mock_info(owner, &[]);
let update = GatewayConfigUpdate {
host: "1.1.1.1:1234".to_string(),
mix_port: 1234,
clients_port: 1235,
location: "home".to_string(),
version: "v1.2.3".to_string(),
};
// try updating a non existing gateway bond
let res = try_update_gateway_config(test.deps_mut(), info.clone(), update.clone());
assert_eq!(
res,
Err(MixnetContractError::NoAssociatedGatewayBond {
owner: Addr::unchecked(owner)
})
);
test.add_dummy_gateway(owner, None);
let vesting_contract = test.vesting_contract();
// attempted to remove on behalf with invalid proxy (current is `None`)
let res = try_update_gateway_config_on_behalf(
test.deps_mut(),
mock_info(vesting_contract.as_ref(), &[]),
update.clone(),
owner.to_string(),
);
assert_eq!(
res,
Err(MixnetContractError::ProxyMismatch {
existing: "None".to_string(),
incoming: vesting_contract.into_string()
})
);
// "normal" update succeeds
let res = try_update_gateway_config(test.deps_mut(), info, update.clone());
assert!(res.is_ok());
// and the config has actually been updated
let bond =
must_get_gateway_bond_by_owner(test.deps().storage, &Addr::unchecked(owner)).unwrap();
assert_eq!(bond.gateway.host, update.host);
assert_eq!(bond.gateway.mix_port, update.mix_port);
assert_eq!(bond.gateway.clients_port, update.clients_port);
assert_eq!(bond.gateway.location, update.location);
assert_eq!(bond.gateway.version, update.version);
}
#[test]
fn updating_gateway_config_with_illegal_proxy() {
let mut test = TestSetup::new();
let illegal_proxy = Addr::unchecked("not-vesting-contract");
let vesting_contract = test.vesting_contract();
let owner = "alice";
test.add_dummy_gateway_with_illegal_proxy(owner, None, illegal_proxy.clone());
let update = GatewayConfigUpdate {
host: "1.1.1.1:1234".to_string(),
mix_port: 1234,
clients_port: 1235,
location: "at home".to_string(),
version: "v1.2.3".to_string(),
};
let res = try_update_gateway_config_on_behalf(
test.deps_mut(),
mock_info(illegal_proxy.as_ref(), &[]),
update,
owner.to_string(),
)
.unwrap_err();
assert_eq!(
res,
MixnetContractError::SenderIsNotVestingContract {
received: illegal_proxy,
vesting_contract
}
)
}
}
@@ -295,7 +295,7 @@ pub(crate) fn try_update_mixnode_config(
}
pub(crate) fn try_update_mixnode_config_on_behalf(
deps: DepsMut,
deps: DepsMut<'_>,
info: MessageInfo,
new_config: MixNodeConfigUpdate,
owner: String,
@@ -308,7 +308,7 @@ pub(crate) fn try_update_mixnode_config_on_behalf(
}
pub(crate) fn _try_update_mixnode_config(
deps: DepsMut,
deps: DepsMut<'_>,
new_config: MixNodeConfigUpdate,
owner: Addr,
proxy: Option<Addr>,
+1 -1
View File
@@ -20,7 +20,7 @@ pub mod test_helpers {
perform_pending_epoch_actions, perform_pending_interval_actions, try_begin_epoch_transition,
};
use crate::interval::{pending_events, storage as interval_storage};
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::mixnet_contract_settings::storage::{self as mixnet_params_storage};
use crate::mixnet_contract_settings::storage::{
minimum_gateway_pledge, minimum_mixnode_pledge, rewarding_denom,
rewarding_validator_address,
+13
View File
@@ -14,6 +14,7 @@ use cosmwasm_std::{
QueryResponse, Response, StdError, StdResult, Timestamp, Uint128,
};
use cw_storage_plus::Bound;
use mixnet_contract_common::gateway::GatewayConfigUpdate;
use mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use mixnet_contract_common::{Gateway, MixId, MixNode};
use semver::Version;
@@ -219,6 +220,9 @@ pub fn execute(
ExecuteMsg::TrackUnbondGateway { owner, amount } => {
try_track_unbond_gateway(&owner, amount, info, deps)
}
ExecuteMsg::UpdateGatewayConfig { new_config } => {
try_update_gateway_config(new_config, info, deps)
}
ExecuteMsg::TransferOwnership { to_address } => {
try_transfer_ownership(to_address, info, deps)
}
@@ -300,6 +304,15 @@ pub fn try_update_mixnode_config(
account.try_update_mixnode_config(new_config, deps.storage)
}
pub fn try_update_gateway_config(
new_config: GatewayConfigUpdate,
info: MessageInfo,
deps: DepsMut,
) -> Result<Response, ContractError> {
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
account.try_update_gateway_config(new_config, deps.storage)
}
pub fn try_update_mixnode_cost_params(
new_costs: MixNodeCostParams,
info: MessageInfo,
@@ -2,6 +2,7 @@ use crate::errors::ContractError;
use contracts_common::signing::MessageSignature;
use cosmwasm_std::{Coin, Env, Response, Storage};
use mixnet_contract_common::{
gateway::GatewayConfigUpdate,
mixnode::{MixNodeConfigUpdate, MixNodeCostParams},
Gateway, MixNode,
};
@@ -64,4 +65,10 @@ pub trait GatewayBondingAccount {
amount: Coin,
storage: &mut dyn Storage,
) -> Result<(), ContractError>;
fn try_update_gateway_config(
&self,
new_config: GatewayConfigUpdate,
storage: &mut dyn Storage,
) -> Result<Response, ContractError>;
}
@@ -4,9 +4,12 @@ use crate::storage::MIXNET_CONTRACT_ADDRESS;
use crate::traits::GatewayBondingAccount;
use contracts_common::signing::MessageSignature;
use cosmwasm_std::{wasm_execute, Coin, Env, Response, Storage, Uint128};
use mixnet_contract_common::{ExecuteMsg as MixnetExecuteMsg, Gateway};
use mixnet_contract_common::{
gateway::GatewayConfigUpdate, ExecuteMsg as MixnetExecuteMsg, Gateway,
};
use vesting_contract_common::events::{
new_vesting_gateway_bonding_event, new_vesting_gateway_unbonding_event,
new_vesting_update_gateway_config_event,
};
use super::Account;
@@ -78,4 +81,22 @@ impl GatewayBondingAccount for Account {
self.remove_gateway_pledge(storage)?;
Ok(())
}
fn try_update_gateway_config(
&self,
new_config: GatewayConfigUpdate,
storage: &mut dyn Storage,
) -> Result<Response, ContractError> {
let msg = MixnetExecuteMsg::UpdateGatewayConfigOnBehalf {
new_config,
owner: self.owner_address().into_string(),
};
let update_gateway_config_msg =
wasm_execute(MIXNET_CONTRACT_ADDRESS.load(storage)?, &msg, vec![])?;
Ok(Response::new()
.add_message(update_gateway_config_msg)
.add_event(new_vesting_update_gateway_config_event()))
}
}
+1
View File
@@ -63,6 +63,7 @@ fn main() {
mixnet::bond::unbond_mixnode,
mixnet::bond::update_mixnode_cost_params,
mixnet::bond::update_mixnode_config,
mixnet::bond::update_gateway_config,
mixnet::bond::get_number_of_mixnode_delegators,
mixnet::bond::get_mix_node_description,
mixnet::bond::get_mixnode_avg_uptime,
@@ -8,6 +8,7 @@ use crate::operations::helpers::{
use crate::state::WalletState;
use crate::{nyxd_client, Gateway, MixNode};
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::{MixId, MixNodeConfigUpdate};
use nym_types::currency::DecCoin;
use nym_types::gateway::GatewayBond;
@@ -227,6 +228,31 @@ pub async fn update_mixnode_config(
)?)
}
#[tauri::command]
pub async fn update_gateway_config(
update: GatewayConfigUpdate,
fee: Option<Fee>,
state: tauri::State<'_, WalletState>,
) -> Result<TransactionExecuteResult, BackendError> {
let guard = state.read().await;
let fee_amount = guard.convert_tx_fee(fee.as_ref());
log::info!(
">>> Update gateway config: update = {}, fee {:?}",
update.to_inline_json(),
fee,
);
let res = guard
.current_client()?
.nyxd
.update_gateway_config(update, fee)
.await?;
log::info!("<<< tx hash = {}", res.transaction_hash);
log::trace!("<<< {:?}", res);
Ok(TransactionExecuteResult::from_execute_result(
res, fee_amount,
)?)
}
#[tauri::command]
pub async fn get_mixnode_avg_uptime(
state: tauri::State<'_, WalletState>,
@@ -1,5 +0,0 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};
@@ -0,0 +1,2 @@
transaction.png
node_modules/
@@ -0,0 +1,27 @@
{
"name": "sdk_wasm_tests",
"version": "1.0.2",
"license": "ISC",
"main": "index.js",
"scripts": {
"test": "mocha --timeout 10000 --require ts-node/register src/tests/*.spec.ts",
"build": "npm run",
"testlocal": "npm run build && npm run test"
},
"dependencies": {
"prettier": "^2.8.4",
"puppeteer": "^19.7.5"
},
"devDependencies": {
"@types/chai": "^4.2.18",
"@types/mocha": "^10.0.1",
"@types/node": "^18.15.3",
"@types/puppeteer": "^7.0.4",
"chai": "^4.3.4",
"mocha": "^10.2.0",
"mochawesome": "^7.1.3",
"puppeteer-debug": "^2.0.0",
"ts-node": "^10.0.0",
"typescript": "^4.3.4"
}
}
@@ -0,0 +1,3 @@
{
"localhost": "http://localhost:3000/"
}
@@ -0,0 +1,7 @@
{
"sender": "#sender",
"recipient": "#recipient",
"id": "#message",
"send_button": "#send-button",
"output": "#output"
}
@@ -0,0 +1,51 @@
import { expect } from 'chai';
const selectors = require('../selectors/attr.json');
import kermit from '../utils/kermit';
const config = require('../config/config.json');
import delay from '../utils/helper';
describe('run base test', async () => {
let browser;
let page;
before(async () => {
browser = await kermit();
page = await browser.newPage();
await page.goto(config.localhost);
await delay(5000);
});
after(async () => {
await page.screenshot({ path: 'transaction.png' });
await browser.close();
});
it('Validate an address can be pasted', async () => {
const senderaddress = await page.evaluate(() => {
return (document.querySelector('#sender') as HTMLInputElement).value;
});
await page.type(selectors.recipient, senderaddress);
});
it('Validate a mesage can be typed', async () => {
await page.click(selectors.id, { clickCount: 3 });
await page.type(selectors.id, "Hi, I'm a test");
});
it('Validate the message can be sent and received', async () => {
await page.click(selectors.send_button);
await delay(1500);
const sentmessage = await page.evaluate(() => {
return (document.querySelector('#output') as Element).firstChild.textContent;
});
const receivedmesage = await page.evaluate(() => {
return (document.querySelector('#output') as Element).lastChild.textContent;
});
console.log(receivedmesage);
console.log(sentmessage);
expect(receivedmesage).contains('received');
expect(sentmessage).contains('sent');
});
});
@@ -0,0 +1,5 @@
export default async function delay(time) {
return new Promise(function (resolve) {
setTimeout(resolve, time);
});
}
@@ -0,0 +1,10 @@
import * as puppeteer from 'puppeteer';
const defaultOptions = {
headless: true,
};
export default async (options = undefined) => {
const puppeterOptions = options === undefined ? defaultOptions : options;
return await puppeteer.launch(puppeterOptions);
};
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": true,
"noImplicitAny": false
},
"include": ["src/tests/*.spec.ts"]
}
+4 -2
View File
@@ -5,8 +5,9 @@ use nym_api_requests::models::{
};
use nym_mixnet_contract_common::rewarding::RewardEstimate;
use nym_mixnet_contract_common::{
Interval as ContractInterval, IntervalRewardParams, IntervalRewardingParamsUpdate, MixNode,
MixNodeConfigUpdate, RewardedSetNodeStatus, RewardingParams, UnbondedMixnode,
GatewayConfigUpdate, Interval as ContractInterval, IntervalRewardParams,
IntervalRewardingParamsUpdate, MixNode, MixNodeConfigUpdate, RewardedSetNodeStatus,
RewardingParams, UnbondedMixnode,
};
use nym_types::account::{Account, AccountEntry, AccountWithMnemonic, Balance};
use nym_types::currency::{CurrencyDenom, DecCoin};
@@ -90,6 +91,7 @@ fn main() {
do_export!(Gas);
do_export!(GasInfo);
do_export!(Gateway);
do_export!(GatewayConfigUpdate);
do_export!(GatewayBond);
do_export!(CurrencyDenom);
do_export!(DecCoin);
@@ -0,0 +1,9 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export interface GatewayConfigUpdate {
host: string;
mix_port: number;
clients_port: number;
location: string;
version: string;
}