diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs index 9b5761bed6..26a766a190 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs @@ -683,6 +683,24 @@ pub trait MixnetSigningClient { .await } + async fn migrate_vested_mixnode(&self, fee: Option) -> Result { + self.execute_mixnet_contract(fee, MixnetExecuteMsg::MigrateVestedMixNode {}, vec![]) + .await + } + + async fn migrate_vested_delegation( + &self, + mix_id: MixId, + fee: Option, + ) -> Result { + self.execute_mixnet_contract( + fee, + MixnetExecuteMsg::MigrateVestedDelegation { mix_id }, + vec![], + ) + .await + } + #[cfg(feature = "contract-testing")] async fn testing_resolve_all_pending_events( &self, @@ -928,6 +946,12 @@ mod tests { MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client .withdraw_delegator_reward_on_behalf(owner.parse().unwrap(), mix_id, None) .ignore(), + MixnetExecuteMsg::MigrateVestedMixNode { .. } => { + client.migrate_vested_mixnode(None).ignore() + } + MixnetExecuteMsg::MigrateVestedDelegation { mix_id } => { + client.migrate_vested_delegation(mix_id, None).ignore() + } #[cfg(feature = "contract-testing")] MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => { diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/vesting_signing_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/vesting_signing_client.rs index 11c449fccd..07472c4262 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/vesting_signing_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/vesting_signing_client.rs @@ -437,6 +437,7 @@ where mod tests { use super::*; use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue}; + use nym_vesting_contract_common::ExecuteMsg; // it's enough that this compiles and clippy is happy about it #[allow(dead_code)] @@ -560,6 +561,9 @@ mod tests { VestingExecuteMsg::UpdateLockedPledgeCap { address, cap } => client .update_locked_pledge_cap(address.parse().unwrap(), cap, None) .ignore(), + // those will never be manually called by clients + ExecuteMsg::TrackMigratedMixnode { .. } => "explicitly_ignored".ignore(), + ExecuteMsg::TrackMigratedDelegation { .. } => "explicitly_ignored".ignore(), }; } } diff --git a/common/commands/src/validator/mixnet/delegators/migrate_vested_delegation.rs b/common/commands/src/validator/mixnet/delegators/migrate_vested_delegation.rs new file mode 100644 index 0000000000..8523e63639 --- /dev/null +++ b/common/commands/src/validator/mixnet/delegators/migrate_vested_delegation.rs @@ -0,0 +1,42 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::context::SigningClient; +use clap::Parser; +use log::info; +use nym_mixnet_contract_common::MixId; +use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient}; + +#[derive(Debug, Parser)] +pub struct Args { + #[clap(long)] + pub mix_id: Option, + + #[clap(long)] + pub identity_key: Option, +} + +pub async fn migrate_vested_delegation(args: Args, client: SigningClient) { + let mix_id = match args.mix_id { + Some(mix_id) => mix_id, + None => { + let identity_key = args + .identity_key + .expect("either mix_id or mix_identity has to be specified"); + let node_details = client + .get_mixnode_details_by_identity(identity_key) + .await + .expect("contract query failed") + .mixnode_details + .expect("mixnode with the specified identity doesnt exist"); + node_details.mix_id() + } + }; + + let res = client + .migrate_vested_delegation(mix_id, None) + .await + .expect("failed to migrate delegation!"); + + info!("migration result: {:?}", res) +} diff --git a/common/commands/src/validator/mixnet/delegators/mod.rs b/common/commands/src/validator/mixnet/delegators/mod.rs index f2cf156c0c..17a5f9fa5c 100644 --- a/common/commands/src/validator/mixnet/delegators/mod.rs +++ b/common/commands/src/validator/mixnet/delegators/mod.rs @@ -7,6 +7,7 @@ pub mod rewards; pub mod delegate_to_mixnode; pub mod delegate_to_multiple_mixnodes; +pub mod migrate_vested_delegation; pub mod query_for_delegations; pub mod undelegate_from_mixnode; pub mod vesting_delegate_to_mixnode; @@ -35,4 +36,6 @@ pub enum MixnetDelegatorsCommands { DelegateVesting(vesting_delegate_to_mixnode::Args), /// Undelegate from a mixnode (when originally using locked tokens) UndelegateVesting(vesting_undelegate_from_mixnode::Args), + /// Migrate the delegation to use liquid tokens + MigrateVestedDelegation(migrate_vested_delegation::Args), } diff --git a/common/commands/src/validator/mixnet/delegators/query_for_delegations.rs b/common/commands/src/validator/mixnet/delegators/query_for_delegations.rs index f29dae6db3..b1a223b603 100644 --- a/common/commands/src/validator/mixnet/delegators/query_for_delegations.rs +++ b/common/commands/src/validator/mixnet/delegators/query_for_delegations.rs @@ -96,6 +96,7 @@ async fn print_delegation_events(events: Vec, client: &Signin mix_id, amount, proxy, + .. } => { if owner.as_str() == client.nyxd.address().as_ref() { table.add_row(vec![ @@ -111,6 +112,7 @@ async fn print_delegation_events(events: Vec, client: &Signin owner, mix_id, proxy, + .. } => { if owner.as_str() == client.nyxd.address().as_ref() { table.add_row(vec![ diff --git a/common/commands/src/validator/mixnet/operators/gateway/gateway_bonding_sign_payload.rs b/common/commands/src/validator/mixnet/operators/gateway/gateway_bonding_sign_payload.rs index 3845a6c7ef..ba19f61867 100644 --- a/common/commands/src/validator/mixnet/operators/gateway/gateway_bonding_sign_payload.rs +++ b/common/commands/src/validator/mixnet/operators/gateway/gateway_bonding_sign_payload.rs @@ -8,7 +8,7 @@ use cosmwasm_std::Coin; use nym_bin_common::output_format::OutputFormat; use nym_mixnet_contract_common::construct_gateway_bonding_sign_payload; use nym_network_defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT}; -use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider}; +use nym_validator_client::nyxd::contract_traits::MixnetQueryClient; #[derive(Debug, Parser)] pub struct Args { @@ -39,10 +39,6 @@ pub struct Args { )] pub amount: u128, - /// Indicates whether the gateway is going to get bonded via a vesting account - #[arg(long)] - pub with_vesting_account: bool, - #[clap(short, long, default_value_t = OutputFormat::default())] output: OutputFormat, } @@ -74,15 +70,8 @@ pub async fn create_payload(args: Args, client: SigningClient) { }; let address = account_id_to_cw_addr(&client.address()); - let proxy = if args.with_vesting_account { - Some(account_id_to_cw_addr( - client.vesting_contract_address().unwrap(), - )) - } else { - None - }; - let payload = construct_gateway_bonding_sign_payload(nonce, address, proxy, coin, gateway); + let payload = construct_gateway_bonding_sign_payload(nonce, address, coin, gateway); let wrapper = DataWrapper::new(payload.to_base58_string().unwrap()); println!("{}", args.output.format(&wrapper)) } diff --git a/common/commands/src/validator/mixnet/operators/mixnode/families/create_family.rs b/common/commands/src/validator/mixnet/operators/mixnode/families/create_family.rs index 6acaca80d2..6e2c664a35 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/families/create_family.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/families/create_family.rs @@ -5,33 +5,21 @@ use crate::context::SigningClient; use clap::Parser; use log::info; use nym_validator_client::nyxd::contract_traits::MixnetSigningClient; -use nym_validator_client::nyxd::contract_traits::VestingSigningClient; #[derive(Debug, Parser)] pub struct Args { /// Label that is going to be used for creating the family #[arg(long)] pub family_label: String, - - /// Indicates whether the family is going to get created via a vesting account - #[arg(long)] - pub with_vesting_account: bool, } pub async fn create_family(args: Args, client: SigningClient) { info!("Create family"); - let res = if args.with_vesting_account { - client - .vesting_create_family(args.family_label, None) - .await - .expect("failed to create family with vesting account") - } else { - client - .create_family(args.family_label, None) - .await - .expect("failed to create family") - }; + let res = client + .create_family(args.family_label, None) + .await + .expect("failed to create family"); info!("Family creation result: {:?}", res); } diff --git a/common/commands/src/validator/mixnet/operators/mixnode/families/create_family_join_permit_sign_payload.rs b/common/commands/src/validator/mixnet/operators/mixnode/families/create_family_join_permit_sign_payload.rs index c81dc35f69..ac397150ea 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/families/create_family_join_permit_sign_payload.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/families/create_family_join_permit_sign_payload.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::context::QueryClient; -use crate::utils::{account_id_to_cw_addr, DataWrapper}; +use crate::utils::DataWrapper; use clap::Parser; use cosmrs::AccountId; use log::info; @@ -10,7 +10,7 @@ use nym_bin_common::output_format::OutputFormat; use nym_crypto::asymmetric::identity; use nym_mixnet_contract_common::construct_family_join_permit; use nym_mixnet_contract_common::families::FamilyHead; -use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider}; +use nym_validator_client::nyxd::contract_traits::MixnetQueryClient; #[derive(Debug, Parser)] pub struct Args { @@ -18,10 +18,6 @@ pub struct Args { #[arg(long)] pub address: AccountId, - /// Indicates whether the member joining the family is going to use the vesting account for joining. - #[arg(long)] - pub with_vesting_account: bool, - // might as well validate the value when parsing the arguments /// Identity of the member for whom we're issuing the permit #[arg(long)] @@ -68,18 +64,9 @@ pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryCli } }; - // let address = account_id_to_cw_addr(&args.address); - let proxy = if args.with_vesting_account { - Some(account_id_to_cw_addr( - client.vesting_contract_address().unwrap(), - )) - } else { - None - }; - let head = FamilyHead::new(mixnode.bond_information.identity()); - let payload = construct_family_join_permit(nonce, head, proxy, args.member.to_base58_string()); + let payload = construct_family_join_permit(nonce, head, args.member.to_base58_string()); let wrapper = DataWrapper::new(payload.to_base58_string().unwrap()); println!("{}", args.output.format(&wrapper)) } diff --git a/common/commands/src/validator/mixnet/operators/mixnode/families/join_family.rs b/common/commands/src/validator/mixnet/operators/mixnode/families/join_family.rs index 411a8412b7..08b4c471c0 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/families/join_family.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/families/join_family.rs @@ -8,7 +8,6 @@ use nym_contracts_common::signing::MessageSignature; use nym_crypto::asymmetric::identity; use nym_mixnet_contract_common::families::FamilyHead; use nym_validator_client::nyxd::contract_traits::MixnetSigningClient; -use nym_validator_client::nyxd::contract_traits::VestingSigningClient; #[derive(Debug, Parser)] pub struct Args { @@ -16,10 +15,6 @@ pub struct Args { #[arg(long)] pub family_head: identity::PublicKey, - /// Indicates whether the member joining the family is going to do so via the vesting contract - #[arg(long)] - pub with_vesting_account: bool, - /// Permission, as provided by the family head, for joining the family #[arg(long)] pub join_permit: MessageSignature, @@ -30,17 +25,10 @@ pub async fn join_family(args: Args, client: SigningClient) { let family_head = FamilyHead::new(args.family_head.to_base58_string()); - let res = if args.with_vesting_account { - client - .vesting_join_family(args.join_permit, family_head, None) - .await - .expect("failed to join family with vesting account") - } else { - client - .join_family(args.join_permit, family_head, None) - .await - .expect("failed to join family") - }; + let res = client + .join_family(args.join_permit, family_head, None) + .await + .expect("failed to join family"); info!("Family join result: {:?}", res); } diff --git a/common/commands/src/validator/mixnet/operators/mixnode/families/leave_family.rs b/common/commands/src/validator/mixnet/operators/mixnode/families/leave_family.rs index 0673be508a..d9c31e3933 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/families/leave_family.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/families/leave_family.rs @@ -7,17 +7,12 @@ use log::info; use nym_crypto::asymmetric::identity; use nym_mixnet_contract_common::families::FamilyHead; use nym_validator_client::nyxd::contract_traits::MixnetSigningClient; -use nym_validator_client::nyxd::contract_traits::VestingSigningClient; #[derive(Debug, Parser)] pub struct Args { /// The head of the family that we intend to leave #[arg(long)] pub family_head: identity::PublicKey, - - /// Indicates whether we joined the family via the vesting contract - #[arg(long)] - pub with_vesting_account: bool, } pub async fn leave_family(args: Args, client: SigningClient) { @@ -25,17 +20,10 @@ pub async fn leave_family(args: Args, client: SigningClient) { let family_head = FamilyHead::new(args.family_head.to_base58_string()); - let res = if args.with_vesting_account { - client - .vesting_leave_family(family_head, None) - .await - .expect("failed to leave family with vesting account") - } else { - client - .leave_family(family_head, None) - .await - .expect("failed to leave family") - }; + let res = client + .leave_family(family_head, None) + .await + .expect("failed to leave family"); info!("Family leave result: {:?}", res); } diff --git a/common/commands/src/validator/mixnet/operators/mixnode/migrate_vested_mixnode.rs b/common/commands/src/validator/mixnet/operators/mixnode/migrate_vested_mixnode.rs new file mode 100644 index 0000000000..95bd9d0573 --- /dev/null +++ b/common/commands/src/validator/mixnet/operators/mixnode/migrate_vested_mixnode.rs @@ -0,0 +1,19 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::context::SigningClient; +use clap::Parser; +use log::info; +use nym_validator_client::nyxd::contract_traits::MixnetSigningClient; + +#[derive(Debug, Parser)] +pub struct Args {} + +pub async fn migrate_vested_mixnode(_args: Args, client: SigningClient) { + let res = client + .migrate_vested_mixnode(None) + .await + .expect("failed to migrate mixnode!"); + + info!("migration result: {:?}", res) +} diff --git a/common/commands/src/validator/mixnet/operators/mixnode/mixnode_bonding_sign_payload.rs b/common/commands/src/validator/mixnet/operators/mixnode/mixnode_bonding_sign_payload.rs index 332de7614e..a492b3a0b6 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/mixnode_bonding_sign_payload.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/mixnode_bonding_sign_payload.rs @@ -11,7 +11,7 @@ use nym_mixnet_contract_common::{construct_mixnode_bonding_sign_payload, MixNode use nym_network_defaults::{ DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT, }; -use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider}; +use nym_validator_client::nyxd::contract_traits::MixnetQueryClient; use nym_validator_client::nyxd::CosmWasmCoin; #[derive(Debug, Parser)] @@ -52,10 +52,6 @@ pub struct Args { )] pub amount: u128, - /// Indicates whether the mixnode is going to get bonded via a vesting account - #[arg(long)] - pub with_vesting_account: bool, - #[clap(short, long, default_value_t = OutputFormat::default())] output: OutputFormat, } @@ -100,16 +96,9 @@ pub async fn create_payload(args: Args, client: SigningClient) { }; let address = account_id_to_cw_addr(&client.address()); - let proxy = if args.with_vesting_account { - Some(account_id_to_cw_addr( - client.vesting_contract_address().unwrap(), - )) - } else { - None - }; let payload = - construct_mixnode_bonding_sign_payload(nonce, address, proxy, coin, mixnode, cost_params); + construct_mixnode_bonding_sign_payload(nonce, address, coin, mixnode, cost_params); let wrapper = DataWrapper::new(payload.to_base58_string().unwrap()); println!("{}", args.output.format(&wrapper)) } diff --git a/common/commands/src/validator/mixnet/operators/mixnode/mod.rs b/common/commands/src/validator/mixnet/operators/mixnode/mod.rs index 6e5283d77e..abb5060e9b 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/mod.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/mod.rs @@ -7,6 +7,7 @@ pub mod bond_mixnode; pub mod decrease_pledge; pub mod families; pub mod keys; +pub mod migrate_vested_mixnode; pub mod mixnode_bonding_sign_payload; pub mod pledge_more; pub mod rewards; @@ -52,4 +53,6 @@ pub enum MixnetOperatorsMixnodeCommands { DecreasePledge(decrease_pledge::Args), /// Decrease pledge with locked tokens DecreasePledgeVesting(vesting_decrease_pledge::Args), + /// Migrate the mixnode to use liquid tokens + MigrateVestedNode(migrate_vested_mixnode::Args), } diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs index e88bfc098b..bb250d7820 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs @@ -271,7 +271,7 @@ pub enum ExecuteMsg { // vesting migration: MigrateVestedMixNode {}, - MigratedVestedDelegation { + MigrateVestedDelegation { mix_id: MixId, }, @@ -388,7 +388,7 @@ impl ExecuteMsg { format!("withdrawing delegator reward from mixnode {mix_id} on behalf") } ExecuteMsg::MigrateVestedMixNode { .. } => "migrate vested mixnode".into(), - ExecuteMsg::MigratedVestedDelegation { .. } => "migrate vested delegation".to_string(), + ExecuteMsg::MigrateVestedDelegation { .. } => "migrate vested delegation".to_string(), #[cfg(feature = "contract-testing")] ExecuteMsg::TestingResolveAllPendingEvents { .. } => { diff --git a/contracts/mixnet-vesting-integration-tests/src/decrease_mixnode_pledge.rs b/contracts/mixnet-vesting-integration-tests/src/decrease_mixnode_pledge.rs deleted file mode 100644 index a9930e23f7..0000000000 --- a/contracts/mixnet-vesting-integration-tests/src/decrease_mixnode_pledge.rs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2023 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use crate::support::helpers::{mix_coin, mix_coins, vesting_owner}; -use crate::support::setup::{TestSetup, MIX_DENOM}; -use cosmwasm_std::Addr; -use cw_multi_test::Executor; -use nym_contracts_common::Percent; -use nym_mixnet_contract_common::error::MixnetContractError; -use nym_mixnet_contract_common::{ContractStateParams, MixNodeCostParams}; -use nym_mixnet_contract_common::{MixOwnershipResponse, QueryMsg as MixnetQueryMsg}; -use nym_vesting_contract_common::{ExecuteMsg as VestingExecuteMsg, VestingContractError}; - -#[test] -fn decrease_mixnode_pledge_from_vesting_account_with_minimum_pledge() { - let mut test = TestSetup::new_simple(); - let vesting_account = "vesting-account"; - - // 0. get the minimum pledge amount - let state_params: ContractStateParams = test - .app - .wrap() - .query_wasm_smart(test.mixnet_contract(), &MixnetQueryMsg::GetStateParams {}) - .unwrap(); - let minimum_pledge = state_params.minimum_mixnode_pledge; - - // 1. create vesting account - let create_msg = VestingExecuteMsg::CreateAccount { - owner_address: vesting_account.to_string(), - staking_address: None, - vesting_spec: None, - cap: None, - }; - - test.app - .execute_contract( - vesting_owner(), - test.vesting_contract(), - &create_msg, - &mix_coins(1_000_000_000), - ) - .unwrap(); - - // 2. bond mixnode with the vesting account - let pledge = minimum_pledge.clone(); - - let cost_params = MixNodeCostParams { - profit_margin_percent: Percent::from_percentage_value(10).unwrap(), - interval_operating_cost: mix_coin(40_000_000), - }; - - let (mix_node, owner_signature) = test.valid_mixnode_with_sig( - vesting_account, - Some(test.vesting_contract()), - cost_params.clone(), - pledge.clone(), - ); - - let bond_msg = VestingExecuteMsg::BondMixnode { - mix_node, - cost_params, - owner_signature, - amount: pledge.clone(), - }; - test.app - .execute_contract( - Addr::unchecked(vesting_account), - test.vesting_contract(), - &bond_msg, - &[], - ) - .unwrap(); - - // 3. try to decrease the pledge - - // trying to decrease by a zero amount - not valid - let decrease_pledge_msg = VestingExecuteMsg::DecreasePledge { - amount: mix_coin(0), - }; - let res_zero = test - .app - .execute_contract( - Addr::unchecked(vesting_account), - test.vesting_contract(), - &decrease_pledge_msg, - &[], - ) - .unwrap_err(); - - assert_eq!( - VestingContractError::EmptyFunds, - res_zero.downcast().unwrap() - ); - - // trying to go below the cap - also not valid - let amount = mix_coin(50_000); - let decrease_pledge_msg = VestingExecuteMsg::DecreasePledge { - amount: amount.clone(), - }; - let res_below = test - .app - .execute_contract( - Addr::unchecked(vesting_account), - test.vesting_contract(), - &decrease_pledge_msg, - &[], - ) - .unwrap_err(); - assert_eq!( - MixnetContractError::InvalidPledgeReduction { - current: pledge.amount, - decrease_by: amount.amount, - minimum: minimum_pledge.amount, - denom: minimum_pledge.denom - }, - res_below.downcast().unwrap() - ) -} - -#[test] -fn decrease_mixnode_pledge_from_vesting_account_with_sufficient_pledge() { - let mut test = TestSetup::new_simple(); - let vesting_account = "vesting-account"; - - // 1. create vesting account - let create_msg = VestingExecuteMsg::CreateAccount { - owner_address: vesting_account.to_string(), - staking_address: None, - vesting_spec: None, - cap: None, - }; - - test.app - .execute_contract( - vesting_owner(), - test.vesting_contract(), - &create_msg, - &mix_coins(10_000_000_000), - ) - .unwrap(); - - // 2. bond mixnode with the vesting account - let pledge = mix_coin(150_000_000); - - let cost_params = MixNodeCostParams { - profit_margin_percent: Percent::from_percentage_value(10).unwrap(), - interval_operating_cost: mix_coin(40_000_000), - }; - - let (mix_node, owner_signature) = test.valid_mixnode_with_sig( - vesting_account, - Some(test.vesting_contract()), - cost_params.clone(), - pledge.clone(), - ); - - let bond_msg = VestingExecuteMsg::BondMixnode { - mix_node, - cost_params, - owner_signature, - amount: pledge, - }; - test.app - .execute_contract( - Addr::unchecked(vesting_account), - test.vesting_contract(), - &bond_msg, - &[], - ) - .unwrap(); - - // 3. try to decrease the pledge - let before: MixOwnershipResponse = test - .app - .wrap() - .query_wasm_smart( - test.mixnet_contract(), - &MixnetQueryMsg::GetOwnedMixnode { - address: vesting_account.to_string(), - }, - ) - .unwrap(); - let balance_before = test - .app - .wrap() - .query_balance(test.vesting_contract(), MIX_DENOM) - .unwrap(); - assert_eq!(balance_before.amount.u128(), 9_850_000_000); - - let decrease_pledge_msg = VestingExecuteMsg::DecreasePledge { - amount: mix_coin(50_000_000), - }; - test.app - .execute_contract( - Addr::unchecked(vesting_account), - test.vesting_contract(), - &decrease_pledge_msg, - &[], - ) - .unwrap(); - - let after_decrease: MixOwnershipResponse = test - .app - .wrap() - .query_wasm_smart( - test.mixnet_contract(), - &MixnetQueryMsg::GetOwnedMixnode { - address: vesting_account.to_string(), - }, - ) - .unwrap(); - - // note: nothing has changed with the pledge because the event hasn't been resolved yet! - assert_eq!(before.address, after_decrease.address); - let before_details = before.mixnode_details.unwrap(); - let after_details = after_decrease.mixnode_details.unwrap(); - assert_eq!( - before_details.rewarding_details, - after_details.rewarding_details - ); - assert_eq!( - before_details.bond_information, - after_details.bond_information - ); - - // but we have the pending change saved now! - assert!(before_details.pending_changes.pledge_change.is_none()); - assert_eq!(Some(1), after_details.pending_changes.pledge_change); - - // 4. resolve events - test.advance_mixnet_epoch(); - - let balance_after = test - .app - .wrap() - .query_balance(test.vesting_contract(), MIX_DENOM) - .unwrap(); - assert_eq!(balance_after.amount.u128(), 9_900_000_000); -} diff --git a/contracts/mixnet-vesting-integration-tests/src/support/helpers.rs b/contracts/mixnet-vesting-integration-tests/src/support/helpers.rs index f739d8556a..a714ccf493 100644 --- a/contracts/mixnet-vesting-integration-tests/src/support/helpers.rs +++ b/contracts/mixnet-vesting-integration-tests/src/support/helpers.rs @@ -12,27 +12,33 @@ pub fn mixnet_owner() -> Addr { Addr::unchecked(MIXNET_OWNER) } +#[allow(unused)] pub fn vesting_owner() -> Addr { Addr::unchecked(VESTING_OWNER) } +#[allow(unused)] pub fn rewarding_validator() -> Addr { Addr::unchecked(REWARDING_VALIDATOR) } +#[allow(unused)] pub fn mix_coins(amount: u128) -> Vec { coins(amount, MIX_DENOM) } +#[allow(unused)] pub fn mix_coin(amount: u128) -> Coin { coin(amount, MIX_DENOM) } +#[allow(unused)] pub fn test_rng() -> ChaCha20Rng { let dummy_seed = [42u8; 32]; ChaCha20Rng::from_seed(dummy_seed) } +#[allow(unused)] pub fn mixnet_contract_wrapper() -> Box> { Box::new( ContractWrapper::new( diff --git a/contracts/mixnet-vesting-integration-tests/src/support/setup.rs b/contracts/mixnet-vesting-integration-tests/src/support/setup.rs index a9fa086160..4ef1b04cba 100644 --- a/contracts/mixnet-vesting-integration-tests/src/support/setup.rs +++ b/contracts/mixnet-vesting-integration-tests/src/support/setup.rs @@ -26,6 +26,7 @@ pub const VESTING_OWNER: &str = "vesting-owner"; pub const REWARDING_VALIDATOR: &str = "rewarding-validator"; pub const MIX_DENOM: &str = "unym"; +#[allow(unused)] pub struct ContractInstantiationResult { mixnet_contract_address: Addr, vesting_contract_address: Addr, @@ -69,6 +70,7 @@ impl TestSetupBuilder { } } +#[allow(unused)] pub struct TestSetup { pub app: App, pub rng: ChaCha20Rng, @@ -76,6 +78,7 @@ pub struct TestSetup { pub mixnet_contract: Addr, } +#[allow(unused)] impl TestSetup { pub fn new_simple() -> Self { TestSetup::new(Default::default(), fixtures::default_mixnet_init_msg()) diff --git a/contracts/mixnet-vesting-integration-tests/src/tests.rs b/contracts/mixnet-vesting-integration-tests/src/tests.rs index d560e38394..826adcfd53 100644 --- a/contracts/mixnet-vesting-integration-tests/src/tests.rs +++ b/contracts/mixnet-vesting-integration-tests/src/tests.rs @@ -1,5 +1,4 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -mod decrease_mixnode_pledge; mod support; diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index f2cb28f81c..cd58e05914 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -257,7 +257,7 @@ pub fn execute( ExecuteMsg::MigrateVestedMixNode { .. } => { crate::vesting_migration::try_migrate_vested_mixnode(deps, info) } - ExecuteMsg::MigratedVestedDelegation { mix_id } => { + ExecuteMsg::MigrateVestedDelegation { mix_id } => { crate::vesting_migration::try_migrate_vested_delegation(deps, info, mix_id) } diff --git a/contracts/mixnet/src/interval/pending_events.rs b/contracts/mixnet/src/interval/pending_events.rs index 60bdaec380..fa44e36ec3 100644 --- a/contracts/mixnet/src/interval/pending_events.rs +++ b/contracts/mixnet/src/interval/pending_events.rs @@ -180,7 +180,7 @@ pub(crate) fn unbond_mixnode( cleanup_post_unbond_mixnode_storage(deps.storage, env, &node_details)?; let response = Response::new() - .send_tokens(&owner, tokens.clone()) + .send_tokens(owner, tokens.clone()) .add_event(new_mixnode_unbonding_event(created_at, mix_id)); Ok(response) @@ -889,7 +889,7 @@ mod tests { try_increase_pledge( test.deps_mut(), env.clone(), - mock_info(owner, &*change.clone()), + mock_info(owner, &change.clone()), ) .unwrap(); diff --git a/contracts/vesting/src/contract.rs b/contracts/vesting/src/contract.rs index fcd3727596..a9ef9401a6 100644 --- a/contracts/vesting/src/contract.rs +++ b/contracts/vesting/src/contract.rs @@ -90,7 +90,6 @@ pub fn execute( ExecuteMsg::TrackDecreasePledge { owner, amount } => { try_track_decrease_mixnode_pledge(&owner, amount, info, deps) } - ExecuteMsg::UnbondGateway {} => try_unbond_gateway(info, deps), ExecuteMsg::TrackUnbondGateway { owner, amount } => { try_track_unbond_gateway(&owner, amount, info, deps) } diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 061b49cc26..c037000b2c 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -656,25 +656,6 @@ dependencies = [ "strsim", ] -[[package]] -name = "clap_complete" -version = "4.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc443334c81a804575546c5a8a79b4913b50e28d69232903604cada1de817ce" -dependencies = [ - "clap", -] - -[[package]] -name = "clap_complete_fig" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fee1d30a51305a6c2ed3fc5709be3c8af626c9c958e04dd9ae94e27bcbce9f" -dependencies = [ - "clap", - "clap_complete", -] - [[package]] name = "clap_derive" version = "4.4.7" @@ -3128,9 +3109,6 @@ dependencies = [ name = "nym-bin-common" version = "0.6.0" dependencies = [ - "clap", - "clap_complete", - "clap_complete_fig", "const-str", "log", "pretty_env_logger", @@ -3283,6 +3261,7 @@ version = "0.1.0" dependencies = [ "async-trait", "http 1.1.0", + "nym-bin-common", "reqwest 0.12.4", "serde", "serde_json", diff --git a/nym-wallet/src-tauri/src/error.rs b/nym-wallet/src-tauri/src/error.rs index 1ed617dc4b..e968f269d4 100644 --- a/nym-wallet/src-tauri/src/error.rs +++ b/nym-wallet/src-tauri/src/error.rs @@ -134,6 +134,10 @@ pub enum BackendError { WalletValidatorConnectionFailed, #[error("No defined default validator URL")] WalletNoDefaultValidator, + #[error( + "this vesting operation has been disabled. please use the non-vesting variant instead." + )] + UnsupportedVestingOperation, #[error(transparent)] WalletError { diff --git a/nym-wallet/src-tauri/src/operations/helpers.rs b/nym-wallet/src-tauri/src/operations/helpers.rs index 9f66f29289..8857e288e8 100644 --- a/nym-wallet/src-tauri/src/operations/helpers.rs +++ b/nym-wallet/src-tauri/src/operations/helpers.rs @@ -12,7 +12,7 @@ use nym_mixnet_contract_common::{ construct_mixnode_bonding_sign_payload, Gateway, GatewayBondingPayload, MixNode, MixNodeCostParams, SignableGatewayBondingMsg, SignableMixNodeBondingMsg, }; -use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider}; +use nym_validator_client::nyxd::contract_traits::MixnetQueryClient; use nym_validator_client::nyxd::error::NyxdError; use nym_validator_client::nyxd::Coin; use nym_validator_client::DirectSigningHttpRpcValidatorClient; @@ -21,7 +21,6 @@ use nym_validator_client::DirectSigningHttpRpcValidatorClient; #[async_trait] pub(crate) trait AddressAndNonceProvider { async fn get_signing_nonce(&self) -> Result; - fn vesting_contract_address(&self) -> Addr; fn cw_address(&self) -> Addr; } @@ -31,30 +30,11 @@ impl AddressAndNonceProvider for DirectSigningHttpRpcValidatorClient { self.nyxd.get_signing_nonce(&self.nyxd.address()).await } - fn vesting_contract_address(&self) -> Addr { - // the call to unchecked is fine here as we're converting directly from `AccountId` - // which must have been a valid bech32 address - Addr::unchecked( - self.nyxd - .vesting_contract_address() - .expect("unknown vesting contract address") - .as_ref(), - ) - } - fn cw_address(&self) -> Addr { self.nyxd.cw_address() } } -fn proxy(client: &P, vesting: bool) -> Option { - if vesting { - Some(client.vesting_contract_address()) - } else { - None - } -} - // since the message has to go back to the user due to the increasing nonce, we might as well sign the entire payload pub(crate) async fn create_mixnode_bonding_sign_payload( client: &P, @@ -63,14 +43,15 @@ pub(crate) async fn create_mixnode_bonding_sign_payload Result { + if vesting { + return Err(BackendError::UnsupportedVestingOperation); + } let sender = client.cw_address(); - let proxy = proxy(client, vesting); let nonce = client.get_signing_nonce().await?; Ok(construct_mixnode_bonding_sign_payload( nonce, sender, - proxy, pledge.into(), mix_node, cost_params, @@ -85,6 +66,9 @@ pub(crate) async fn verify_mixnode_bonding_sign_payload Result<(), BackendError> { + if vesting { + return Err(BackendError::UnsupportedVestingOperation); + } let identity_key = identity::PublicKey::from_base58_string(&mix_node.identity_key)?; let signature = identity::Signature::from_bytes(msg_signature.as_ref())?; @@ -118,10 +102,12 @@ pub(crate) async fn create_gateway_bonding_sign_payload Result { + if vesting { + return Err(BackendError::UnsupportedVestingOperation); + } let payload = GatewayBondingPayload::new(gateway); let sender = client.cw_address(); - let proxy = proxy(client, vesting); - let content = ContractMessageContent::new(sender, proxy, vec![pledge.into()], payload); + let content = ContractMessageContent::new(sender, vec![pledge.into()], payload); let nonce = client.get_signing_nonce().await?; Ok(SignableMessage::new(nonce, content)) @@ -134,6 +120,9 @@ pub(crate) async fn verify_gateway_bonding_sign_payload Result<(), BackendError> { + if vesting { + return Err(BackendError::UnsupportedVestingOperation); + } let identity_key = identity::PublicKey::from_base58_string(&gateway.identity_key)?; let signature = identity::Signature::from_bytes(msg_signature.as_ref())?; @@ -170,7 +159,6 @@ mod tests { struct MockClient { address: Addr, - vesting_contract: Addr, signing_nonce: Nonce, } @@ -180,10 +168,6 @@ mod tests { Ok(self.signing_nonce) } - fn vesting_contract_address(&self) -> Addr { - self.vesting_contract.clone() - } - fn cw_address(&self) -> Addr { self.address.clone() } @@ -211,7 +195,6 @@ mod tests { let dummy_account = Addr::unchecked("n16t2umcd83zjpl5puyuuq6lgmy4p3qedjd8ynn6"); let dummy_client = MockClient { address: dummy_account, - vesting_contract: Addr::unchecked("n17tj0a0w6v7r2dc54rnkzfza6s8hxs87rj273a5"), signing_nonce: 42, }; @@ -315,7 +298,6 @@ mod tests { let dummy_account = Addr::unchecked("n16t2umcd83zjpl5puyuuq6lgmy4p3qedjd8ynn6"); let dummy_client = MockClient { address: dummy_account, - vesting_contract: Addr::unchecked("n17tj0a0w6v7r2dc54rnkzfza6s8hxs87rj273a5"), signing_nonce: 42, }; diff --git a/tools/nym-cli/src/validator/mixnet/delegators/mod.rs b/tools/nym-cli/src/validator/mixnet/delegators/mod.rs index 8ccfbd59a3..08e5df592a 100644 --- a/tools/nym-cli/src/validator/mixnet/delegators/mod.rs +++ b/tools/nym-cli/src/validator/mixnet/delegators/mod.rs @@ -34,7 +34,10 @@ pub(crate) async fn execute( } nym_cli_commands::validator::mixnet::delegators::MixnetDelegatorsCommands::List(args) => { nym_cli_commands::validator::mixnet::delegators::query_for_delegations::execute(args, create_signing_client_with_nym_api(global_args, network_details)?).await - } + }, + nym_cli_commands::validator::mixnet::delegators::MixnetDelegatorsCommands::MigrateVestedDelegation(args) => { + nym_cli_commands::validator::mixnet::delegators::migrate_vested_delegation::migrate_vested_delegation(args, create_signing_client(global_args, network_details)?).await + }, } Ok(()) } diff --git a/tools/nym-cli/src/validator/mixnet/operators/mixnodes/mod.rs b/tools/nym-cli/src/validator/mixnet/operators/mixnodes/mod.rs index b3cf6d4e28..ac2d301f4f 100644 --- a/tools/nym-cli/src/validator/mixnet/operators/mixnodes/mod.rs +++ b/tools/nym-cli/src/validator/mixnet/operators/mixnodes/mod.rs @@ -48,7 +48,10 @@ pub(crate) async fn execute( nym_cli_commands::validator::mixnet::operators::mixnode::MixnetOperatorsMixnodeCommands::DecreasePledgeVesting(args) => { nym_cli_commands::validator::mixnet::operators::mixnode::vesting_decrease_pledge::vesting_decrease_pledge(args, create_signing_client(global_args, network_details)?).await } - _ => unreachable!(), + nym_cli_commands::validator::mixnet::operators::mixnode::MixnetOperatorsMixnodeCommands::MigrateVestedNode(args) => { + nym_cli_commands::validator::mixnet::operators::mixnode::migrate_vested_mixnode::migrate_vested_mixnode(args, create_signing_client(global_args, network_details)?).await + } + _ => unreachable!() } Ok(()) }