diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 1fb526afa4..f71026cddb 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -1165,21 +1165,6 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" -[[package]] -name = "mixnet-vesting-integration-tests" -version = "0.1.0" -dependencies = [ - "cosmwasm-std", - "cw-multi-test", - "nym-contracts-common", - "nym-crypto", - "nym-mixnet-contract", - "nym-mixnet-contract-common", - "nym-vesting-contract", - "nym-vesting-contract-common", - "rand_chacha", -] - [[package]] name = "num-bigint" version = "0.4.6" diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml index 0b23099771..fbd31e1a55 100644 --- a/contracts/Cargo.toml +++ b/contracts/Cargo.toml @@ -4,7 +4,6 @@ members = [ "coconut-dkg", "ecash", "mixnet", - "mixnet-vesting-integration-tests", "nym-pool", "multisig/cw3-flex-multisig", "multisig/cw4-group", diff --git a/contracts/mixnet-vesting-integration-tests/Cargo.toml b/contracts/mixnet-vesting-integration-tests/Cargo.toml deleted file mode 100644 index 361885e353..0000000000 --- a/contracts/mixnet-vesting-integration-tests/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "mixnet-vesting-integration-tests" -version = "0.1.0" -authors = { workspace = true } -edition = { workspace = true } -license = { workspace = true } -repository = { workspace = true } -publish = false - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - -# cosmwasm dependencies -cosmwasm-std = { workspace = true } -cw-multi-test = { workspace = true } - -# contracts dependencies -nym-mixnet-contract-common = { workspace = true } -nym-vesting-contract-common = { workspace = true } -nym-contracts-common = { workspace = true } - -nym-mixnet-contract = { workspace = true } -nym-vesting-contract = { workspace = true } - -# other local dependencies -nym-crypto = { workspace = true, features = ["asymmetric", "rand"] } - -# external dependencies -rand_chacha = "0.3" - -[[test]] -name = "mixnet-vesting-test" -path = "src/tests.rs" diff --git a/contracts/mixnet-vesting-integration-tests/src/support/fixtures.rs b/contracts/mixnet-vesting-integration-tests/src/support/fixtures.rs deleted file mode 100644 index 2df1a87e35..0000000000 --- a/contracts/mixnet-vesting-integration-tests/src/support/fixtures.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2023 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use crate::support::setup::{MIX_DENOM, REWARDING_VALIDATOR}; -use cosmwasm_std::Decimal; -use nym_contracts_common::Percent; -use nym_mixnet_contract_common::reward_params::RewardedSetParams; -use nym_mixnet_contract_common::InitialRewardingParams; -use std::time::Duration; - -pub fn default_mixnet_init_msg() -> nym_mixnet_contract_common::InstantiateMsg { - nym_mixnet_contract_common::InstantiateMsg { - rewarding_validator_address: REWARDING_VALIDATOR.to_string(), - vesting_contract_address: "placeholder".to_string(), - rewarding_denom: MIX_DENOM.to_string(), - epochs_in_interval: 720, - epoch_duration: Duration::from_secs(60 * 60), - initial_rewarding_params: InitialRewardingParams { - initial_reward_pool: Decimal::from_atomics(250_000_000_000_000u128, 0).unwrap(), - initial_staking_supply: Decimal::from_atomics(223_000_000_000_000u128, 0).unwrap(), - staking_supply_scale_factor: Percent::hundred(), - sybil_resistance: Percent::from_percentage_value(30).unwrap(), - active_set_work_factor: Decimal::from_atomics(10u32, 0).unwrap(), - interval_pool_emission: Percent::from_percentage_value(2).unwrap(), - rewarded_set_params: RewardedSetParams { - entry_gateways: 70, - exit_gateways: 50, - mixnodes: 120, - standby: 0, - }, - }, - current_nym_node_version: "1.1.10".to_string(), - version_score_weights: Default::default(), - version_score_params: Default::default(), - profit_margin: Default::default(), - interval_operating_cost: Default::default(), - key_validity_in_epochs: None, - } -} diff --git a/contracts/mixnet-vesting-integration-tests/src/support/helpers.rs b/contracts/mixnet-vesting-integration-tests/src/support/helpers.rs deleted file mode 100644 index a714ccf493..0000000000 --- a/contracts/mixnet-vesting-integration-tests/src/support/helpers.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2023 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use crate::support::setup::{MIXNET_OWNER, MIX_DENOM, REWARDING_VALIDATOR, VESTING_OWNER}; -use cosmwasm_std::{coin, coins, Addr, Coin, Empty}; -use cw_multi_test::{Contract, ContractWrapper}; -use rand_chacha::rand_core::SeedableRng; -use rand_chacha::ChaCha20Rng; - -#[allow(unused)] -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( - mixnet_contract::contract::execute, - mixnet_contract::contract::instantiate, - mixnet_contract::contract::query, - ) - .with_migrate(mixnet_contract::contract::migrate), - ) -} - -pub fn vesting_contract_wrapper() -> Box> { - Box::new( - ContractWrapper::new( - vesting_contract::contract::execute, - vesting_contract::contract::instantiate, - vesting_contract::contract::query, - ) - .with_migrate(vesting_contract::contract::migrate), - ) -} diff --git a/contracts/mixnet-vesting-integration-tests/src/support/mod.rs b/contracts/mixnet-vesting-integration-tests/src/support/mod.rs deleted file mode 100644 index ea9fb30983..0000000000 --- a/contracts/mixnet-vesting-integration-tests/src/support/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2023 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -pub mod fixtures; -pub mod helpers; -pub mod setup; diff --git a/contracts/mixnet-vesting-integration-tests/src/support/setup.rs b/contracts/mixnet-vesting-integration-tests/src/support/setup.rs deleted file mode 100644 index 90aa13526f..0000000000 --- a/contracts/mixnet-vesting-integration-tests/src/support/setup.rs +++ /dev/null @@ -1,480 +0,0 @@ -// Copyright 2023 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use crate::support::fixtures; -use crate::support::helpers::{ - mixnet_contract_wrapper, rewarding_validator, test_rng, vesting_contract_wrapper, -}; -use cosmwasm_std::{coins, Addr, Coin, Decimal, Timestamp}; -use cw_multi_test::{App, AppBuilder, Executor}; -use nym_contracts_common::signing::{ContractMessageContent, MessageSignature, Nonce}; -use nym_crypto::asymmetric::ed25519; -use nym_mixnet_contract_common::nym_node::{EpochAssignmentResponse, Role, RolesMetadataResponse}; -use nym_mixnet_contract_common::reward_params::{NodeRewardingParameters, Performance}; -use nym_mixnet_contract_common::{ - CurrentIntervalResponse, MixnodeBondingPayload, NodeCostParams, RewardedSet, RewardingParams, - RoleAssignment, SignableMixNodeBondingMsg, -}; -use nym_mixnet_contract_common::{ - ExecuteMsg as MixnetExecuteMsg, MixNode, QueryMsg as MixnetQueryMsg, -}; -use rand_chacha::ChaCha20Rng; -use std::collections::HashMap; - -// our global accounts that should always get some coins at the start -pub const MIXNET_OWNER: &str = "mixnet-owner"; -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, -} - -#[allow(unused)] -pub struct TestSetupBuilder { - mixnet_init_msg: nym_mixnet_contract_common::InstantiateMsg, - initial_balances: HashMap>, -} - -#[allow(unused)] -impl TestSetupBuilder { - pub fn new() -> Self { - TestSetupBuilder { - mixnet_init_msg: fixtures::default_mixnet_init_msg(), - initial_balances: Default::default(), - } - } - - pub fn with_mixnet_init_msg( - mut self, - mixnet_init_msg: nym_mixnet_contract_common::InstantiateMsg, - ) -> Self { - self.mixnet_init_msg = mixnet_init_msg; - self - } - - pub fn with_initial_balances(mut self, initial_balances: HashMap>) -> Self { - self.initial_balances = initial_balances; - self - } - - pub fn with_initial_balance(mut self, addr: impl Into, balance: Vec) -> Self { - self.initial_balances.insert(Addr::unchecked(addr), balance); - self - } - - pub fn build(self) -> TestSetup { - TestSetup::new(self.initial_balances, self.mixnet_init_msg) - } -} - -#[allow(unused)] -pub struct TestSetup { - pub app: App, - pub rng: ChaCha20Rng, - - pub mixnet_contract: Addr, -} - -#[allow(unused)] -impl TestSetup { - pub fn new_simple() -> Self { - TestSetup::new(Default::default(), fixtures::default_mixnet_init_msg()) - } - - pub fn new( - initial_balances: HashMap>, - custom_mixnet_init: nym_mixnet_contract_common::InstantiateMsg, - ) -> Self { - let (app, contracts) = instantiate_contracts(initial_balances, Some(custom_mixnet_init)); - TestSetup { - app, - rng: test_rng(), - mixnet_contract: contracts.mixnet_contract_address, - } - } - - pub fn mixnet_contract(&self) -> Addr { - self.mixnet_contract.clone() - } - - pub fn skip_to_current_epoch_end(&mut self) { - let current_interval: CurrentIntervalResponse = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetCurrentIntervalDetails {}, - ) - .unwrap(); - let epoch_end = current_interval.interval.current_epoch_end_unix_timestamp(); - - self.app.update_block(|current_block| { - // skip few blocks just in case - current_block.height += 10; - current_block.time = Timestamp::from_seconds(epoch_end as u64) - }) - } - - fn get_rewarded_set(&self) -> RewardedSet { - let metadata: RolesMetadataResponse = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetRewardedSetMetadata {}, - ) - .unwrap(); - - let entry: EpochAssignmentResponse = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetRoleAssignment { - role: Role::EntryGateway, - }, - ) - .unwrap(); - assert_eq!(entry.epoch_id, metadata.metadata.epoch_id); - - let exit: EpochAssignmentResponse = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetRoleAssignment { - role: Role::ExitGateway, - }, - ) - .unwrap(); - assert_eq!(exit.epoch_id, metadata.metadata.epoch_id); - - let layer1: EpochAssignmentResponse = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetRoleAssignment { role: Role::Layer1 }, - ) - .unwrap(); - assert_eq!(layer1.epoch_id, metadata.metadata.epoch_id); - - let layer2: EpochAssignmentResponse = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetRoleAssignment { role: Role::Layer2 }, - ) - .unwrap(); - assert_eq!(layer2.epoch_id, metadata.metadata.epoch_id); - - let layer3: EpochAssignmentResponse = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetRoleAssignment { role: Role::Layer3 }, - ) - .unwrap(); - assert_eq!(layer3.epoch_id, metadata.metadata.epoch_id); - - let standby: EpochAssignmentResponse = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetRoleAssignment { - role: Role::Standby, - }, - ) - .unwrap(); - assert_eq!(standby.epoch_id, metadata.metadata.epoch_id); - - RewardedSet { - entry_gateways: entry.nodes, - exit_gateways: exit.nodes, - layer1: layer1.nodes, - layer2: layer2.nodes, - layer3: layer3.nodes, - standby: standby.nodes, - } - } - - pub fn full_mixnet_epoch_operations(&mut self) { - let rewarded_set = self.get_rewarded_set(); - - let current_params: RewardingParams = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetRewardingParams {}, - ) - .unwrap(); - // TODO: handle paging - - // begin epoch transition - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::BeginEpochTransition {}, - &[], - ) - .unwrap(); - - let work = - Decimal::one() / Decimal::from_ratio(rewarded_set.rewarded_set_size() as u64, 1u64); - let params = NodeRewardingParameters::new(Performance::hundred(), work); - - let mut nodes = rewarded_set - .layer1 - .iter() - .chain(rewarded_set.layer2.iter()) - .chain(rewarded_set.layer3.iter()) - .chain(rewarded_set.entry_gateways.iter()) - .chain(rewarded_set.exit_gateways.iter()) - .chain(rewarded_set.standby.iter()) - .copied() - .collect::>(); - - nodes.sort(); - - // reward - for (node_id) in nodes { - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::RewardNode { node_id, params }, - &[], - ) - .unwrap(); - } - - // events - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::ReconcileEpochEvents { limit: None }, - &[], - ) - .unwrap(); - - // don't bother changing the active set, use the same node for update and advance - - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::AssignRoles { - assignment: RoleAssignment { - role: Role::EntryGateway, - nodes: rewarded_set.entry_gateways, - }, - }, - &[], - ) - .unwrap(); - - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::AssignRoles { - assignment: RoleAssignment { - role: Role::ExitGateway, - nodes: rewarded_set.exit_gateways, - }, - }, - &[], - ) - .unwrap(); - - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::AssignRoles { - assignment: RoleAssignment { - role: Role::Layer1, - nodes: rewarded_set.layer1, - }, - }, - &[], - ) - .unwrap(); - - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::AssignRoles { - assignment: RoleAssignment { - role: Role::Layer2, - nodes: rewarded_set.layer2, - }, - }, - &[], - ) - .unwrap(); - - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::AssignRoles { - assignment: RoleAssignment { - role: Role::Layer3, - nodes: rewarded_set.layer3, - }, - }, - &[], - ) - .unwrap(); - - self.app - .execute_contract( - rewarding_validator(), - self.mixnet_contract(), - &MixnetExecuteMsg::AssignRoles { - assignment: RoleAssignment { - role: Role::Standby, - nodes: rewarded_set.standby, - }, - }, - &[], - ) - .unwrap(); - } - - pub fn advance_mixnet_epoch(&mut self) { - self.skip_to_current_epoch_end(); - self.full_mixnet_epoch_operations(); - } - - pub fn valid_mixnode_with_sig( - &mut self, - owner: &str, - cost_params: NodeCostParams, - stake: Coin, - ) -> (MixNode, MessageSignature) { - let signing_nonce: Nonce = self - .app - .wrap() - .query_wasm_smart( - self.mixnet_contract(), - &MixnetQueryMsg::GetSigningNonce { - address: owner.to_string(), - }, - ) - .unwrap(); - - let keypair = ed25519::KeyPair::new(&mut self.rng); - let identity_key = keypair.public_key().to_base58_string(); - let legit_sphinx_keys = nym_crypto::asymmetric::x25519::KeyPair::new(&mut self.rng); - - let mixnode = MixNode { - identity_key, - sphinx_key: legit_sphinx_keys.public_key().to_base58_string(), - host: "mix.node.org".to_string(), - mix_port: 1789, - verloc_port: 1790, - http_api_port: 8000, - version: "1.1.14".to_string(), - }; - - let payload = MixnodeBondingPayload::new(mixnode.clone(), cost_params); - let content = ContractMessageContent::new(Addr::unchecked(owner), vec![stake], payload); - let sign_payload = SignableMixNodeBondingMsg::new(signing_nonce, content); - let plaintext = sign_payload.to_plaintext().unwrap(); - let signature = keypair.private_key().sign(plaintext); - let msg_signature = MessageSignature::from(signature.to_bytes().as_ref()); - - (mixnode, msg_signature) - } -} - -pub fn instantiate_contracts( - mut initial_funds: HashMap>, - custom_mixnet_init: Option, -) -> (App, ContractInstantiationResult) { - // add our global addresses to the map - initial_funds.insert( - Addr::unchecked(MIXNET_OWNER), - coins(100_000_000_000, MIX_DENOM), - ); - - initial_funds.insert( - Addr::unchecked(VESTING_OWNER), - coins(100_000_000_000, MIX_DENOM), - ); - - initial_funds.insert( - Addr::unchecked(REWARDING_VALIDATOR), - coins(1_000_000_000_000, MIX_DENOM), - ); - - let mut app = AppBuilder::new().build(|router, _api, storage| { - for (addr, funds) in initial_funds { - router - .bank - .init_balance(storage, &addr, funds.clone()) - .unwrap() - } - }); - - let mixnet_code_id = app.store_code(mixnet_contract_wrapper()); - let vesting_code_id = app.store_code(vesting_contract_wrapper()); - - let mixnet_contract_address = app - .instantiate_contract( - mixnet_code_id, - Addr::unchecked(MIXNET_OWNER), - &custom_mixnet_init.unwrap_or(fixtures::default_mixnet_init_msg()), - &[], - "mixnet-contract", - Some(MIXNET_OWNER.to_string()), - ) - .unwrap(); - - let vesting_contract_address = app - .instantiate_contract( - vesting_code_id, - Addr::unchecked(VESTING_OWNER), - &nym_vesting_contract_common::InitMsg { - mixnet_contract_address: mixnet_contract_address.to_string(), - mix_denom: MIX_DENOM.to_string(), - }, - &[], - "vesting-contract", - Some(VESTING_OWNER.to_string()), - ) - .unwrap(); - - // now fix up vesting contract address... - app.migrate_contract( - Addr::unchecked(MIXNET_OWNER), - mixnet_contract_address.clone(), - &nym_mixnet_contract_common::MigrateMsg { - vesting_contract_address: Some(vesting_contract_address.to_string()), - unsafe_skip_state_updates: Some(true), - }, - mixnet_code_id, - ) - .unwrap(); - - ( - app, - ContractInstantiationResult { - mixnet_contract_address, - vesting_contract_address, - }, - ) -} diff --git a/contracts/mixnet-vesting-integration-tests/src/tests.rs b/contracts/mixnet-vesting-integration-tests/src/tests.rs deleted file mode 100644 index 826adcfd53..0000000000 --- a/contracts/mixnet-vesting-integration-tests/src/tests.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2023 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -mod support;