diff --git a/aptos-move/framework/aptos-framework/sources/governed_gas_pool.move b/aptos-move/framework/aptos-framework/sources/governed_gas_pool.move index 830b00499ec..3891b1e0010 100644 --- a/aptos-move/framework/aptos-framework/sources/governed_gas_pool.move +++ b/aptos-move/framework/aptos-framework/sources/governed_gas_pool.move @@ -10,6 +10,7 @@ module aptos_framework::governed_gas_pool { use aptos_framework::object::{Self}; use aptos_framework::aptos_coin::AptosCoin; use aptos_framework::coin::{Self, Coin}; + use aptos_framework::event::{Self, EventHandle}; use std::features; use aptos_framework::signer; use aptos_framework::aptos_account::Self; @@ -20,8 +21,15 @@ module aptos_framework::governed_gas_pool { #[test_only] use aptos_framework::aptos_coin::Self; + friend aptos_framework::stake; + const MODULE_SALT: vector = b"aptos_framework::governed_gas_pool"; + /// Event emitted when token are withdraw from the pool + struct WithdrawStakingRewardEvent has drop, store { + amount: u64, + } + /// The Governed Gas Pool /// Internally, this is a simply wrapper around a resource account. struct GovernedGasPool has key { @@ -29,6 +37,12 @@ module aptos_framework::governed_gas_pool { signer_capability: SignerCapability, } + /// Contains added variable needed for the GovernedGasPool staking reward update. + struct GovernedGasPoolExtension has key { + deposited_treasury_counter: u64, + withdraw_staking_reward_events: EventHandle, + } + /// Address of APT Primary Fungible Store inline fun primary_fungible_store_address(account: address): address { object::create_user_derived_object_address(account, @aptos_fungible_asset) @@ -71,8 +85,33 @@ module aptos_framework::governed_gas_pool { move_to(aptos_framework, GovernedGasPool{ signer_capability: governed_gas_pool_signer_cap, }); + + move_to(aptos_framework, GovernedGasPoolExtension{ + deposited_treasury_counter: 0, + withdraw_staking_reward_events: account::new_event_handle(aptos_framework), + }); + } + + /// Initializes the governed gas pool extension alone. + /// @param aptos_framework The signer of the aptos_framework module. + public entry fun initialize_governed_gas_pool_extension( + aptos_framework: &signer, + ) { + system_addresses::assert_aptos_framework(aptos_framework); + + // return if the governed gas extension has already been initialized + if (exists(signer::address_of(aptos_framework))) { + return + }; + + move_to(aptos_framework, GovernedGasPoolExtension{ + deposited_treasury_counter: 0, + withdraw_staking_reward_events: account::new_event_handle(aptos_framework), + }); } + + /// Initialize the governed gas pool as a module /// @param aptos_framework The signer of the aptos_framework module. fun init_module(aptos_framework: &signer) { @@ -95,6 +134,12 @@ module aptos_framework::governed_gas_pool { signer::address_of(&governed_gas_signer()) } + #[view] + /// Return the amount of treasury deposited. + public fun get_treasury_deposited(): u64 acquires GovernedGasPoolExtension { + borrow_global(@aptos_framework).deposited_treasury_counter + } + /// Funds the destination account with a given amount of coin. /// @param account The account to be funded. /// @param amount The amount of coin to be funded. @@ -155,13 +200,24 @@ module aptos_framework::governed_gas_pool { /// @param gas_payer The address of the account that paid the gas fees. /// @param gas_fee The amount of gas fees to be deposited. public(friend) fun deposit_gas_fee_v2(gas_payer: address, gas_fee: u64) acquires GovernedGasPool { - if (features::operations_default_to_fa_apt_store_enabled()) { + if (features::operations_default_to_fa_apt_store_enabled()) { deposit_from_fungible_store(gas_payer, gas_fee); } else { deposit_from(gas_payer, gas_fee); }; } + /// Deposits from the treasury account. Treasury deposit are recorded. + /// @param treasury_account The address of the account that paid the treasury. + /// @param amount The amount of treasury to be deposited. + public entry fun deposit_treasury(treasury_account: &signer, amount: u64) acquires GovernedGasPool, GovernedGasPoolExtension { + let treasury_account_address = signer::address_of(treasury_account); + deposit_from(treasury_account_address, amount); + + let ggp = borrow_global_mut(@aptos_framework); + ggp.deposited_treasury_counter = ggp.deposited_treasury_counter + amount; + } + #[view] /// Gets the balance of a specified coin type in the governed gas pool. /// @return The balance of the coin in the pool. @@ -170,6 +226,38 @@ module aptos_framework::governed_gas_pool { coin::balance(pool_address) } + /// Withdraws coins from the governed gas pool. + /// + /// This function allows friend modules to withdraw a specified amount of a given + /// `CoinType` from the governed gas pool. It uses the internal signer of the + /// governed gas pool to authorize the withdrawal. + /// + /// @param amount The amount of coins to withdraw from the pool. + /// @return A `Coin` resource containing the withdrawn amount. + public(friend) fun withdraw_staking_reward( + amount: u64 + ): Coin acquires GovernedGasPool, GovernedGasPoolExtension { + let balance = get_balance(); + assert!(balance >= amount, 0); // insufficient balance + let ggpv2 = borrow_global_mut(@aptos_framework); + + event::emit_event( + &mut ggpv2.withdraw_staking_reward_events, + WithdrawStakingRewardEvent { + amount, + }, + ); + + // Withdraw reward coin. + coin::withdraw(&governed_gas_signer(), amount) + } + + /// Register Aptos coin with Governed gas signer. + public(friend) fun register_coin() acquires GovernedGasPool { + let s = governed_gas_signer(); + coin::register(&s); + } + #[test_only] /// The AptosCoin mint capability struct AptosCoinMintCapability has key { @@ -222,6 +310,9 @@ module aptos_framework::governed_gas_pool { aptos_framework: &signer, ) { + // Create framework account to be able to send event. + aptos_framework::account::create_account_for_test(@aptos_framework); + // initialize the AptosCoin module let (burn_cap, mint_cap) = aptos_coin::initialize_for_test(aptos_framework); @@ -361,4 +452,39 @@ module aptos_framework::governed_gas_pool { // initialize the governed gas pool again, no abort initialize(aptos_framework, vector::empty()); } + + + #[test(aptos_framework = @aptos_framework, treasury = @0xdddd)] + /// Add some treasury to the governed gas pool. + /// + /// @param aptos_framework is the signer of the aptos_framework module. + fun test_deposite_treasury_and_counter(aptos_framework: &signer, treasury: &signer) acquires GovernedGasPool, GovernedGasPoolExtension, AptosCoinMintCapability { + + // initialize the modules + initialize_for_test(aptos_framework); + + // create the depositor account and fund it + aptos_account::create_account(signer::address_of(treasury)); + mint_for_test(signer::address_of(treasury), 1000); + + // get the balances for the depositor and the governed gas pool + let treasury_balance = coin::balance(signer::address_of(treasury)); + let governed_gas_pool_balance = coin::balance(governed_gas_pool_address()); + + // deposit some coin into the governed gas pool + deposit_treasury(treasury, 100); + + // check the balances after the deposit + assert!(coin::balance(signer::address_of(treasury)) == treasury_balance - 100, 1); + assert!(coin::balance(governed_gas_pool_address()) == governed_gas_pool_balance + 100, 2); + assert!(get_treasury_deposited() == 100, 3); + + let withdraw = withdraw_staking_reward(10); + assert!(coin::balance(governed_gas_pool_address()) == governed_gas_pool_balance + 100 - 10, 4); + assert!(get_treasury_deposited() == 100, 5); + assert!(coin::value(&withdraw) == 10, 6); + + coin::deposit(@0xdddd, withdraw); + } + } diff --git a/aptos-move/framework/aptos-framework/sources/stake.move b/aptos-move/framework/aptos-framework/sources/stake.move index 9639ffa8ff0..5e6cefdab7c 100644 --- a/aptos-move/framework/aptos-framework/sources/stake.move +++ b/aptos-move/framework/aptos-framework/sources/stake.move @@ -34,6 +34,7 @@ module aptos_framework::stake { use aptos_framework::system_addresses; use aptos_framework::staking_config::{Self, StakingConfig, StakingRewardsConfig}; use aptos_framework::chain_status; + use aptos_framework::governed_gas_pool; friend aptos_framework::block; friend aptos_framework::genesis; @@ -1231,8 +1232,7 @@ module aptos_framework::stake { /// pending inactive validators so they no longer can vote. /// 4. The validator's voting power in the validator set is updated to be the corresponding staking pool's voting /// power. - public(friend) fun on_new_epoch( - ) acquires StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + public(friend) fun on_new_epoch() acquires StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { let validator_set = borrow_global_mut(@aptos_framework); let config = staking_config::get(); let validator_perf = borrow_global_mut(@aptos_framework); @@ -1353,7 +1353,6 @@ module aptos_framework::stake { validator_consensus_infos_from_validator_set(validator_set) } - public fun next_validator_consensus_infos(): vector acquires ValidatorSet, ValidatorPerformance, StakePool, ValidatorFees, ValidatorConfig { // Init. let cur_validator_set = borrow_global(@aptos_framework); @@ -1644,7 +1643,7 @@ module aptos_framework::stake { } } - /// Mint rewards corresponding to current epoch's `stake` and `num_successful_votes`. + /// Get rewards from the Governed Gas Pool corresponding to current epoch's `stake` and `num_successful_votes`. fun distribute_rewards( stake: &mut Coin, num_successful_proposals: u64, @@ -1665,8 +1664,12 @@ module aptos_framework::stake { 0 }; if (rewards_amount > 0) { - let mint_cap = &borrow_global(@aptos_framework).mint_cap; - let rewards = coin::mint(rewards_amount, mint_cap); + let rewards = if (features::stake_reward_using_treasury_enabled()) { + governed_gas_pool::withdraw_staking_reward(rewards_amount) + } else { + let mint_cap = &borrow_global(@aptos_framework).mint_cap; + coin::mint(rewards_amount, mint_cap) + }; coin::merge(stake, rewards); }; rewards_amount @@ -1778,6 +1781,7 @@ module aptos_framework::stake { use aptos_framework::reconfiguration_state; use aptos_framework::validator_consensus_info; use aptos_framework::validator_consensus_info::ValidatorConsensusInfo; + #[test_only] use aptos_std::fixed_point64; @@ -1788,7 +1792,23 @@ module aptos_framework::stake { const LOCKUP_CYCLE_SECONDS: u64 = 3600; #[test_only] - public fun initialize_for_test(aptos_framework: &signer) { + public fun seed_governed_gas_pool( + aptos_framework: &signer, amount: u64 + ) acquires AptosCoinCapabilities { + let mint_cap = &borrow_global(@aptos_framework).mint_cap; + let coins = coin::mint(amount, mint_cap); + // Initialize the governed gas pool + let seed: vector = b"test"; + governed_gas_pool::initialize(aptos_framework, seed); + let pool_addr = governed_gas_pool::governed_gas_pool_address(); + if (!coin::is_account_registered(pool_addr)) { + governed_gas_pool::register_coin(); + }; + coin::deposit(pool_addr, coins); + } + + #[test_only] + public fun initialize_for_test(aptos_framework: &signer) acquires AptosCoinCapabilities { reconfiguration_state::initialize(aptos_framework); initialize_for_test_custom(aptos_framework, 100, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 100, 1000000); } @@ -1800,7 +1820,7 @@ module aptos_framework::stake { operator: &signer, pool_address: address, should_end_epoch: bool, - ) acquires AptosCoinCapabilities, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { let pk_bytes = bls12381::public_key_to_bytes(pk); let pop_bytes = bls12381::proof_of_possession_to_bytes(pop); rotate_consensus_key(operator, pool_address, pk_bytes, pop_bytes); @@ -1812,7 +1832,7 @@ module aptos_framework::stake { #[test_only] public fun fast_forward_to_unlock(pool_address: address) - acquires AptosCoinCapabilities, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + acquires StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { let expiration_time = get_lockup_secs(pool_address); timestamp::update_global_time_for_test_secs(expiration_time); end_epoch(); @@ -1829,7 +1849,13 @@ module aptos_framework::stake { rewards_rate_numerator: u64, rewards_rate_denominator: u64, voting_power_increase_limit: u64, - ) { + ) acquires AptosCoinCapabilities { + // Create framework account to be able to declare governance reward withdraw event + aptos_framework::account::create_account_for_test(@aptos_framework); + + // Test using treasure. + features::change_feature_flags_for_testing(aptos_framework, vector[features::get_stake_reward_using_treasury_feature()], vector[]); + timestamp::set_time_has_started_for_testing(aptos_framework); reconfiguration_state::initialize(aptos_framework); if (!exists(@aptos_framework)) { @@ -1851,6 +1877,9 @@ module aptos_framework::stake { store_aptos_coin_mint_cap(aptos_framework, mint_cap); coin::destroy_burn_cap(burn_cap); }; + + // Seed a big balance once so reward withdrawals never underflow the pool. + seed_governed_gas_pool(aptos_framework, 1_000_000_000_000_000); } // This function assumes the stake module already the capability to mint aptos coins. @@ -1881,7 +1910,7 @@ module aptos_framework::stake { amount: u64, should_join_validator_set: bool, should_end_epoch: bool, - ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AptosCoinCapabilities, AllowedValidators, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { let validator_address = signer::address_of(validator); if (!account::exists_at(signer::address_of(validator))) { account::create_account_for_test(validator_address); @@ -2064,7 +2093,7 @@ module aptos_framework::stake { public entry fun test_end_to_end( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, true, true); @@ -2121,7 +2150,7 @@ module aptos_framework::stake { public entry fun test_inactive_validator_with_existing_lockup_join_validator_set( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, false, false); @@ -2147,7 +2176,7 @@ module aptos_framework::stake { public entry fun test_cannot_reduce_lockup( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, false, false); @@ -2156,7 +2185,7 @@ module aptos_framework::stake { increase_lockup(validator); // Reduce recurring lockup to 0. staking_config::update_recurring_lockup_duration_secs(aptos_framework, 1); - // INcrease lockup should now fail because the new lockup < old lockup. + // Increase lockup should now fail because the new lockup < old lockup. increase_lockup(validator); } @@ -2166,7 +2195,7 @@ module aptos_framework::stake { aptos_framework: &signer, validator_1: &signer, validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { // Only 50% voting power increase is allowed in each epoch. initialize_for_test_custom(aptos_framework, 50, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 10, 50); let (_sk_1, pk_1, pop_1) = generate_identity(); @@ -2188,7 +2217,7 @@ module aptos_framework::stake { aptos_framework: &signer, validator_1: &signer, validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test_custom(aptos_framework, 50, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 10, 10000); // Need 1 validator to be in the active validator set so joining limit works. let (_sk_1, pk_1, pop_1) = generate_identity(); @@ -2210,7 +2239,7 @@ module aptos_framework::stake { aptos_framework: &signer, validator_1: &signer, validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { // 100% voting power increase is allowed in each epoch. initialize_for_test_custom(aptos_framework, 50, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 10, 100); // Need 1 validator to be in the active validator set so joining limit works. @@ -2230,7 +2259,7 @@ module aptos_framework::stake { public entry fun test_pending_active_validator_leaves_validator_set( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); // Validator joins but epoch hasn't ended, so the validator is still pending_active. let (_sk, pk, pop) = generate_identity(); @@ -2254,7 +2283,7 @@ module aptos_framework::stake { public entry fun test_active_validator_cannot_add_more_stake_than_limit_in_multiple_epochs( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { // Only 50% voting power increase is allowed in each epoch. initialize_for_test_custom(aptos_framework, 50, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 10, 50); // Add initial stake and join the validator set. @@ -2276,7 +2305,7 @@ module aptos_framework::stake { public entry fun test_active_validator_cannot_add_more_stake_than_limit( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { // Only 50% voting power increase is allowed in each epoch. initialize_for_test_custom(aptos_framework, 50, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 10, 50); let (_sk, pk, pop) = generate_identity(); @@ -2290,7 +2319,7 @@ module aptos_framework::stake { public entry fun test_active_validator_unlock_partial_stake( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { // Reward rate = 10%. initialize_for_test_custom(aptos_framework, 50, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 10, 100); let (_sk, pk, pop) = generate_identity(); @@ -2316,7 +2345,7 @@ module aptos_framework::stake { public entry fun test_active_validator_can_withdraw_all_stake_and_rewards_at_once( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, true, true); @@ -2345,7 +2374,7 @@ module aptos_framework::stake { timestamp::fast_forward_seconds(LOCKUP_CYCLE_SECONDS); end_epoch(); assert_validator_state(validator_address, 0, 103, 0, 0, 0); - // Validator ahs been kicked out of the validator set as their stake is 0 now. + // Validator has been kicked out of the validator set as their stake is 0 now. assert!(get_validator_state(validator_address) == VALIDATOR_STATUS_INACTIVE, 4); } @@ -2353,7 +2382,7 @@ module aptos_framework::stake { public entry fun test_active_validator_unlocking_more_than_available_stake_should_cap( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, false, false); @@ -2367,7 +2396,7 @@ module aptos_framework::stake { public entry fun test_active_validator_withdraw_should_cap_by_inactive_stake( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); // Initial balance = 900 (idle) + 100 (staked) = 1000. let (_sk, pk, pop) = generate_identity(); @@ -2392,7 +2421,7 @@ module aptos_framework::stake { public entry fun test_active_validator_can_reactivate_pending_inactive_stake( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, true, true); @@ -2411,7 +2440,7 @@ module aptos_framework::stake { public entry fun test_active_validator_reactivate_more_than_available_pending_inactive_stake_should_cap( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, true, true); @@ -2428,7 +2457,7 @@ module aptos_framework::stake { public entry fun test_active_validator_having_insufficient_remaining_stake_after_withdrawal_gets_kicked( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, true, true); @@ -2456,7 +2485,7 @@ module aptos_framework::stake { aptos_framework: &signer, validator: &signer, validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk_1, pk_1, pop_1) = generate_identity(); let (_sk_2, pk_2, pop_2) = generate_identity(); @@ -2500,7 +2529,7 @@ module aptos_framework::stake { aptos_framework: &signer, validator: &signer, validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk_1, pk_1, pop_1) = generate_identity(); let (_sk_2, pk_2, pop_2) = generate_identity(); @@ -2531,7 +2560,7 @@ module aptos_framework::stake { aptos_framework: &signer, validator_1: &signer, validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { // Only 50% voting power increase is allowed in each epoch. initialize_for_test_custom(aptos_framework, 50, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 10, 50); let (_sk_1, pk_1, pop_1) = generate_identity(); @@ -2552,7 +2581,7 @@ module aptos_framework::stake { validator_1: &signer, validator_2: &signer, validator_3: &signer - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { let validator_1_address = signer::address_of(validator_1); let validator_2_address = signer::address_of(validator_2); let validator_3_address = signer::address_of(validator_3); @@ -2646,7 +2675,7 @@ module aptos_framework::stake { public entry fun test_delegated_staking_with_owner_cap( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test_custom(aptos_framework, 100, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 100, 100); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 0, false, false); @@ -2724,7 +2753,7 @@ module aptos_framework::stake { public entry fun test_validator_cannot_leave_post_genesis( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test_custom(aptos_framework, 100, 10000, LOCKUP_CYCLE_SECONDS, false, 1, 100, 100); let (_sk, pk, pop) = generate_identity(); initialize_test_validator(&pk, &pop, validator, 100, false, false); @@ -2825,8 +2854,8 @@ module aptos_framework::stake { validator_2: &signer, validator_3: &signer, validator_4: &signer, - validator_5: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + validator_5: &signer + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { let v1_addr = signer::address_of(validator_1); let v2_addr = signer::address_of(validator_2); let v3_addr = signer::address_of(validator_3); @@ -2889,7 +2918,7 @@ module aptos_framework::stake { aptos_framework: &signer, validator_1: &signer, validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let validator_1_address = signer::address_of(validator_1); @@ -2936,8 +2965,8 @@ module aptos_framework::stake { public entry fun test_validator_rewards_rate_decrease_over_time( aptos_framework: &signer, validator_1: &signer, - validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + validator_2: &signer + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let genesis_time_in_secs = timestamp::now_seconds(); @@ -2967,6 +2996,10 @@ module aptos_framework::stake { fixed_point64::create_from_rational(50, 100), ); features::change_feature_flags_for_testing(aptos_framework, vector[features::get_periodical_reward_rate_decrease_feature()], vector[]); + // Make sure that periodical reward rate decrease is enabled. + assert!(features::periodical_reward_rate_decrease_enabled(), 0); + // Make sure that stake reward using treasury is enabled. + assert!(features::stake_reward_using_treasury_enabled(), 0); // For some reason, this epoch is very long. It has been 1 year since genesis when the epoch ends. timestamp::fast_forward_seconds(one_year_in_secs - EPOCH_DURATION * 3); @@ -2993,7 +3026,7 @@ module aptos_framework::stake { public entry fun test_update_performance_statistics_should_not_fail_due_to_out_of_bounds( aptos_framework: &signer, validator: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let validator_address = signer::address_of(validator); @@ -3044,7 +3077,6 @@ module aptos_framework::stake { validator: &signer, ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorSet { initialize_for_test_custom(aptos_framework, 50, 10000, LOCKUP_CYCLE_SECONDS, true, 1, 100, 100); - // Call initialize_stake_owner, which only initializes the stake pool but not validator config. let validator_address = signer::address_of(validator); account::create_account_for_test(validator_address); @@ -3116,7 +3148,7 @@ module aptos_framework::stake { aptos_framework: &signer, validator_1: &signer, validator_2: &signer, - ) acquires AllowedValidators, OwnerCapability, StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { initialize_for_test(aptos_framework); let (_sk_1, pk_1, pop_1) = generate_identity(); let (_sk_2, pk_2, pop_2) = generate_identity(); @@ -3132,8 +3164,7 @@ module aptos_framework::stake { } #[test_only] - public fun end_epoch( - ) acquires StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { + public fun end_epoch() acquires StakePool, AptosCoinCapabilities, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { // Set the number of blocks to 1, to give out rewards to non-failing validators. set_validator_perf_at_least_one_block(); timestamp::fast_forward_seconds(EPOCH_DURATION); @@ -3237,14 +3268,18 @@ module aptos_framework::stake { validator_2: &signer, validator_3: &signer, ) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees { - // Make sure that fees collection and distribution is enabled. features::change_feature_flags_for_testing(aptos_framework, vector[COLLECT_AND_DISTRIBUTE_GAS_FEES], vector[]); - assert!(features::collect_and_distribute_gas_fees(), 0); // Initialize staking and validator fees table. initialize_for_test(aptos_framework); initialize_validator_fees(aptos_framework); + // Make sure that fees collection and distribution is enabled. + assert!(features::collect_and_distribute_gas_fees(), 0); + // Make sure that stake reward using treasury is enabled. + assert!(features::stake_reward_using_treasury_enabled(), 0); + + let validator_1_address = signer::address_of(validator_1); let validator_2_address = signer::address_of(validator_2); let validator_3_address = signer::address_of(validator_3); @@ -3263,7 +3298,7 @@ module aptos_framework::stake { add_transaction_fee(validator_2_address, mint_coins(500)); add_transaction_fee(validator_1_address, mint_coins(200)); - // Fess have to be assigned to the right validators, but not + // Fees have to be assigned to the right validators, but not // distributed yet. assert!(get_validator_fee(validator_1_address) == 300, 0); assert!(get_validator_fee(validator_2_address) == 500, 0); @@ -3274,7 +3309,7 @@ module aptos_framework::stake { end_epoch(); - // Epoch ended. Validators must have recieved their rewards and, most importantly, + // Epoch ended. Validators must have received their rewards and, most importantly, // their fees. assert_no_fees_for_validator(validator_1_address); assert_no_fees_for_validator(validator_2_address); diff --git a/aptos-move/framework/aptos-framework/sources/staking_proxy.move b/aptos-move/framework/aptos-framework/sources/staking_proxy.move index 26d1aa33372..d6da569a3cd 100644 --- a/aptos-move/framework/aptos-framework/sources/staking_proxy.move +++ b/aptos-move/framework/aptos-framework/sources/staking_proxy.move @@ -90,6 +90,9 @@ module aptos_framework::staking_proxy { let operator_1_address = signer::address_of(operator_1); let operator_2_address = signer::address_of(operator_2); let new_operator_address = signer::address_of(new_operator); + + aptos_framework::account::create_account_for_test(@aptos_framework); + vesting::setup( aptos_framework, &vector[owner_address, operator_1_address, operator_2_address, new_operator_address]); staking_contract::setup_staking_contract(aptos_framework, owner, operator_1, INITIAL_BALANCE, 0); @@ -135,6 +138,9 @@ module aptos_framework::staking_proxy { let operator_1_address = signer::address_of(operator_1); let operator_2_address = signer::address_of(operator_2); let new_operator_address = signer::address_of(new_operator); + + aptos_framework::account::create_account_for_test(@aptos_framework); + vesting::setup( aptos_framework, &vector[owner_address, operator_1_address, operator_2_address, new_operator_address]); staking_contract::setup_staking_contract(aptos_framework, owner, operator_2, INITIAL_BALANCE, 0); diff --git a/aptos-move/framework/move-stdlib/sources/configs/features.move b/aptos-move/framework/move-stdlib/sources/configs/features.move index c270ebd1cf7..94456d10516 100644 --- a/aptos-move/framework/move-stdlib/sources/configs/features.move +++ b/aptos-move/framework/move-stdlib/sources/configs/features.move @@ -624,6 +624,17 @@ module std::features { is_enabled(DECOMMISSION_CORE_RESOURCES) } + /// Whether the staking rewards are mint (diseable) or withdraw from the gouverned gas pool treasury (enable). + /// + /// Lifetime: permanent + const STAKE_REWARD_USING_TREASURY: u64 = 223; + + public fun get_stake_reward_using_treasury_feature(): u64 { STAKE_REWARD_USING_TREASURY } + + public fun stake_reward_using_treasury_enabled(): bool acquires Features { + is_enabled(STAKE_REWARD_USING_TREASURY) + } + // ============================================================================================ // Feature Flag Implementation diff --git a/movement-migration/framework-upgrades/scripts/feature-flag-reconfig.move b/movement-migration/framework-upgrades/scripts/feature-flag-reconfig.move index 4892551ebf9..6bfc2ec7818 100644 --- a/movement-migration/framework-upgrades/scripts/feature-flag-reconfig.move +++ b/movement-migration/framework-upgrades/scripts/feature-flag-reconfig.move @@ -16,6 +16,7 @@ script { 67, // ConcurrentFungibleBalance 40, // VMBinaryFormat7 74, // EnumTypes + 223, // STAKE_REWARD_USING_TREASURY ]; let disabled_blob: vector = vector[ @@ -26,7 +27,6 @@ script { 54, // KeylessAccountsWithPasskeys 71, // AtomicBridge 72, // NativeBridge - 73, // GovernedGasPool ]; features::change_feature_flags(&core_signer, enabled_blob, disabled_blob);