diff --git a/contracts/account-nft/tests/tests/helpers/mock_env_builder.rs b/contracts/account-nft/tests/tests/helpers/mock_env_builder.rs index 054b98b1..23d87265 100644 --- a/contracts/account-nft/tests/tests/helpers/mock_env_builder.rs +++ b/contracts/account-nft/tests/tests/helpers/mock_env_builder.rs @@ -161,7 +161,6 @@ impl MockEnvBuilder { perps: "n/a".to_string(), keeper_fee_config: Default::default(), perps_liquidation_bonus_ratio: Decimal::percent(60), - governance: "n/a".to_string(), }, }, &[], diff --git a/contracts/credit-manager/src/error.rs b/contracts/credit-manager/src/error.rs index aa2b2902..c2605ec2 100644 --- a/contracts/credit-manager/src/error.rs +++ b/contracts/credit-manager/src/error.rs @@ -135,6 +135,9 @@ pub enum ContractError { #[error("Duplicate voting power thresholds")] DuplicateVotingPowerThresholds, + #[error("Lowest tier must have min_voting_power equal to 0")] + LowestTierMinVotingPowerMustBeZero, + #[error("Discount percentage must be less than or equal to 100%")] InvalidDiscountPercentage, diff --git a/contracts/credit-manager/src/query.rs b/contracts/credit-manager/src/query.rs index 5ed9ea8a..e95d6183 100644 --- a/contracts/credit-manager/src/query.rs +++ b/contracts/credit-manager/src/query.rs @@ -21,10 +21,10 @@ use crate::{ error::ContractResult, staking::get_account_tier_and_discount, state::{ - ACCOUNT_KINDS, ACCOUNT_NFT, COIN_BALANCES, DEBT_SHARES, FEE_TIER_CONFIG, GOVERNANCE, - HEALTH_CONTRACT, INCENTIVES, KEEPER_FEE_CONFIG, MAX_SLIPPAGE, MAX_UNLOCKING_POSITIONS, - ORACLE, OWNER, PARAMS, PERPS, PERPS_LB_RATIO, RED_BANK, REWARDS_COLLECTOR, SWAPPER, - SWAP_FEE, TOTAL_DEBT_SHARES, TRIGGER_ORDERS, VAULTS, VAULT_POSITIONS, ZAPPER, + ACCOUNT_KINDS, ACCOUNT_NFT, COIN_BALANCES, DEBT_SHARES, FEE_TIER_CONFIG, HEALTH_CONTRACT, + INCENTIVES, KEEPER_FEE_CONFIG, MAX_SLIPPAGE, MAX_UNLOCKING_POSITIONS, ORACLE, OWNER, + PARAMS, PERPS, PERPS_LB_RATIO, RED_BANK, REWARDS_COLLECTOR, SWAPPER, SWAP_FEE, + TOTAL_DEBT_SHARES, TRIGGER_ORDERS, VAULTS, VAULT_POSITIONS, ZAPPER, }, utils::debt_shares_to_amount, vault::vault_utilization_in_deposit_cap_denom, @@ -70,7 +70,6 @@ pub fn query_config(deps: Deps) -> ContractResult { rewards_collector: REWARDS_COLLECTOR.may_load(deps.storage)?, keeper_fee_config: KEEPER_FEE_CONFIG.load(deps.storage)?, perps_liquidation_bonus_ratio: PERPS_LB_RATIO.load(deps.storage)?, - governance: GOVERNANCE.load(deps.storage)?.into(), }) } diff --git a/contracts/credit-manager/src/staking.rs b/contracts/credit-manager/src/staking.rs index 4b2ac3b4..f31038fe 100644 --- a/contracts/credit-manager/src/staking.rs +++ b/contracts/credit-manager/src/staking.rs @@ -83,6 +83,13 @@ impl StakingTierManager { // Check for descending order assert_tiers_sorted_descending(&voting_powers)?; + // Ensure the lowest tier requires min_voting_power == 0 + if let Some(lowest) = self.config.tiers.last() { + if !lowest.min_voting_power.is_zero() { + return Err(ContractError::LowestTierMinVotingPowerMustBeZero); + } + } + Ok(()) } diff --git a/contracts/credit-manager/tests/tests/test_staking_tiers.rs b/contracts/credit-manager/tests/tests/test_staking_tiers.rs index 7cea0fad..0e69bf49 100644 --- a/contracts/credit-manager/tests/tests/test_staking_tiers.rs +++ b/contracts/credit-manager/tests/tests/test_staking_tiers.rs @@ -449,7 +449,7 @@ fn test_validation_single_tier_valid() { let config = FeeTierConfig { tiers: vec![FeeTier { id: "single".to_string(), - min_voting_power: Uint128::new(1000), + min_voting_power: Uint128::zero(), discount_pct: Decimal::percent(25), }], }; @@ -544,7 +544,7 @@ fn test_validation_valid_voting_power_format() { let config = FeeTierConfig { tiers: vec![FeeTier { id: "tier_1".to_string(), - min_voting_power: Uint128::new(1000), + min_voting_power: Uint128::new(0), discount_pct: Decimal::percent(50), }], }; @@ -559,7 +559,7 @@ fn test_validation_discount_100_percent() { let config = FeeTierConfig { tiers: vec![FeeTier { id: "tier_1".to_string(), - min_voting_power: Uint128::new(1000), + min_voting_power: Uint128::new(0), discount_pct: Decimal::one(), // 100% discount - now valid! }], }; @@ -574,7 +574,7 @@ fn test_validation_discount_over_100_percent() { let config = FeeTierConfig { tiers: vec![FeeTier { id: "tier_1".to_string(), - min_voting_power: Uint128::new(1000), + min_voting_power: Uint128::new(0), discount_pct: Decimal::percent(150), // 150% discount! }], }; @@ -590,7 +590,7 @@ fn test_validation_discount_99_percent_valid() { let config = FeeTierConfig { tiers: vec![FeeTier { id: "tier_1".to_string(), - min_voting_power: Uint128::new(1000), + min_voting_power: Uint128::zero(), discount_pct: Decimal::percent(99), // 99% discount - valid! }], }; @@ -605,7 +605,7 @@ fn test_validation_zero_discount_valid() { let config = FeeTierConfig { tiers: vec![FeeTier { id: "tier_1".to_string(), - min_voting_power: Uint128::new(1000), + min_voting_power: Uint128::new(0), discount_pct: Decimal::zero(), // 0% discount - valid! }], }; @@ -703,8 +703,9 @@ fn test_validation_max_tier_size( for i in 0..tier_count { tiers.push(FeeTier { id: format!("tier_{}", i), - min_voting_power: Uint128::new(((tier_count - i) * 1000) as u128), // Descending order - discount_pct: Decimal::percent((i * 5) as u64), // 0% to max + // Ensure strictly descending and the final tier has min_voting_power == 0 + min_voting_power: Uint128::new(((tier_count - i - 1) * 1000) as u128), + discount_pct: Decimal::percent((i * 5) as u64), }); } diff --git a/contracts/health/tests/tests/helpers/mock_env_builder.rs b/contracts/health/tests/tests/helpers/mock_env_builder.rs index bab04e2a..96d7c0f7 100644 --- a/contracts/health/tests/tests/helpers/mock_env_builder.rs +++ b/contracts/health/tests/tests/helpers/mock_env_builder.rs @@ -188,7 +188,6 @@ impl MockEnvBuilder { perps: "n/a".to_string(), keeper_fee_config: Default::default(), perps_liquidation_bonus_ratio: Decimal::percent(60), - governance: "n/a".to_string(), }, }, &[], diff --git a/packages/types/src/credit_manager/query.rs b/packages/types/src/credit_manager/query.rs index 35c85444..614aa769 100644 --- a/packages/types/src/credit_manager/query.rs +++ b/packages/types/src/credit_manager/query.rs @@ -273,7 +273,6 @@ pub struct ConfigResponse { pub rewards_collector: Option, pub keeper_fee_config: KeeperFeeConfig, pub perps_liquidation_bonus_ratio: Decimal, - pub governance: String, } #[cw_serde] diff --git a/schemas/mars-credit-manager/mars-credit-manager.json b/schemas/mars-credit-manager/mars-credit-manager.json index a6428d87..8ad9d0e5 100644 --- a/schemas/mars-credit-manager/mars-credit-manager.json +++ b/schemas/mars-credit-manager/mars-credit-manager.json @@ -6977,7 +6977,6 @@ "title": "ConfigResponse", "type": "object", "required": [ - "governance", "health_contract", "incentives", "keeper_fee_config", @@ -6999,9 +6998,6 @@ "null" ] }, - "governance": { - "type": "string" - }, "health_contract": { "type": "string" }, diff --git a/scripts/health/pkg-web/index_bg.wasm b/scripts/health/pkg-web/index_bg.wasm index 789a7db3..1c76a658 100644 Binary files a/scripts/health/pkg-web/index_bg.wasm and b/scripts/health/pkg-web/index_bg.wasm differ diff --git a/scripts/types/generated/mars-credit-manager/MarsCreditManager.types.ts b/scripts/types/generated/mars-credit-manager/MarsCreditManager.types.ts index 9c514189..4302200b 100644 --- a/scripts/types/generated/mars-credit-manager/MarsCreditManager.types.ts +++ b/scripts/types/generated/mars-credit-manager/MarsCreditManager.types.ts @@ -865,7 +865,6 @@ export interface VaultUtilizationResponse { } export interface ConfigResponse { account_nft?: string | null - governance: string health_contract: string incentives: string keeper_fee_config: KeeperFeeConfig