Skip to content

Commit

Permalink
[Cherry pick] Allow to set the beneficiary for operator (#11032)
Browse files Browse the repository at this point in the history
* [Stake] Allow to set the beneficiary for operator (#10455)

* Updated `distribute_internal` to use `aptos_account::deposit_coins` instead of `coin::deposit`

* Allows operators to set beneficiaries

* Update lib.rs (#10861)

* Update lib.rs (#11029)

This enables OPERATOR_BENEFICIARY_CHANGE in the devent to release (v1.8.4).
  • Loading branch information
junkil-park authored Nov 22, 2023
1 parent 9156cc7 commit 8beaf59
Show file tree
Hide file tree
Showing 15 changed files with 1,263 additions and 339 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub enum FeatureFlag {
SponsoredAutomaticAccountCreation,
FeePayerAccountOptional,
LimitMaxIdentifierLength,
OperatorBeneficiaryChange,
}

fn generate_features_blob(writer: &CodeWriter, data: &[u64]) {
Expand Down Expand Up @@ -226,6 +227,7 @@ impl From<FeatureFlag> for AptosFeatureFlag {
},
FeatureFlag::FeePayerAccountOptional => AptosFeatureFlag::FEE_PAYER_ACCOUNT_OPTIONAL,
FeatureFlag::LimitMaxIdentifierLength => AptosFeatureFlag::LIMIT_MAX_IDENTIFIER_LENGTH,
FeatureFlag::OperatorBeneficiaryChange => AptosFeatureFlag::OPERATOR_BENEFICIARY_CHANGE,
}
}
}
Expand Down Expand Up @@ -288,6 +290,7 @@ impl From<AptosFeatureFlag> for FeatureFlag {
},
AptosFeatureFlag::FEE_PAYER_ACCOUNT_OPTIONAL => FeatureFlag::FeePayerAccountOptional,
AptosFeatureFlag::LIMIT_MAX_IDENTIFIER_LENGTH => FeatureFlag::LimitMaxIdentifierLength,
AptosFeatureFlag::OPERATOR_BENEFICIARY_CHANGE => FeatureFlag::OperatorBeneficiaryChange,
}
}
}
Expand Down
270 changes: 250 additions & 20 deletions aptos-move/framework/aptos-framework/doc/delegation_pool.md

Large diffs are not rendered by default.

442 changes: 214 additions & 228 deletions aptos-move/framework/aptos-framework/doc/staking_contract.md

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions aptos-move/framework/aptos-framework/doc/vesting.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ withdrawable, admin can call admin_withdraw to withdraw all funds to the vesting
- [Function `reset_beneficiary`](#0x1_vesting_reset_beneficiary)
- [Function `set_management_role`](#0x1_vesting_set_management_role)
- [Function `set_beneficiary_resetter`](#0x1_vesting_set_beneficiary_resetter)
- [Function `set_beneficiary_for_operator`](#0x1_vesting_set_beneficiary_for_operator)
- [Function `get_role_holder`](#0x1_vesting_get_role_holder)
- [Function `get_vesting_account_signer`](#0x1_vesting_get_vesting_account_signer)
- [Function `get_vesting_account_signer_internal`](#0x1_vesting_get_vesting_account_signer_internal)
Expand Down Expand Up @@ -133,6 +134,7 @@ withdrawable, admin can call admin_withdraw to withdraw all funds to the vesting
- [Function `reset_beneficiary`](#@Specification_1_reset_beneficiary)
- [Function `set_management_role`](#@Specification_1_set_management_role)
- [Function `set_beneficiary_resetter`](#@Specification_1_set_beneficiary_resetter)
- [Function `set_beneficiary_for_operator`](#@Specification_1_set_beneficiary_for_operator)
- [Function `get_role_holder`](#@Specification_1_get_role_holder)
- [Function `get_vesting_account_signer`](#@Specification_1_get_vesting_account_signer)
- [Function `get_vesting_account_signer_internal`](#@Specification_1_get_vesting_account_signer_internal)
Expand Down Expand Up @@ -2460,6 +2462,34 @@ account.



</details>

<a name="0x1_vesting_set_beneficiary_for_operator"></a>

## Function `set_beneficiary_for_operator`

Set the beneficiary for the operator.


<pre><code><b>public</b> entry <b>fun</b> <a href="vesting.md#0x1_vesting_set_beneficiary_for_operator">set_beneficiary_for_operator</a>(operator: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, new_beneficiary: <b>address</b>)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> entry <b>fun</b> <a href="vesting.md#0x1_vesting_set_beneficiary_for_operator">set_beneficiary_for_operator</a>(
operator: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
new_beneficiary: <b>address</b>,
) {
<a href="staking_contract.md#0x1_staking_contract_set_beneficiary_for_operator">staking_contract::set_beneficiary_for_operator</a>(operator, new_beneficiary);
}
</code></pre>



</details>

<a name="0x1_vesting_get_role_holder"></a>
Expand Down Expand Up @@ -3465,6 +3495,22 @@ This address should be deterministic for the same admin and vesting contract cre



<a name="@Specification_1_set_beneficiary_for_operator"></a>

### Function `set_beneficiary_for_operator`


<pre><code><b>public</b> entry <b>fun</b> <a href="vesting.md#0x1_vesting_set_beneficiary_for_operator">set_beneficiary_for_operator</a>(operator: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, new_beneficiary: <b>address</b>)
</code></pre>




<pre><code><b>pragma</b> verify = <b>false</b>;
</code></pre>



<a name="@Specification_1_get_role_holder"></a>

### Function `get_role_holder`
Expand Down
279 changes: 216 additions & 63 deletions aptos-move/framework/aptos-framework/sources/delegation_pool.move

Large diffs are not rendered by default.

197 changes: 173 additions & 24 deletions aptos-move/framework/aptos-framework/sources/staking_contract.move

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,16 @@ spec aptos_framework::staking_contract {
aborts_if simple_map::spec_contains_key(staking_contracts, new_operator);
}

spec set_beneficiary_for_operator(operator: &signer, new_beneficiary: address) {
// TODO: temporary mockup
pragma verify = false;
}

spec beneficiary_for_operator(operator: address): address {
// TODO: temporary mockup
pragma verify = false;
}

/// Staking_contract exists the stacker/operator pair.
spec distribute(staker: address, operator: address) {
// TODO: Call `distribute_internal` and could not verify `update_distribution_pool`.
Expand Down
97 changes: 96 additions & 1 deletion aptos-move/framework/aptos-framework/sources/vesting.move
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,14 @@ module aptos_framework::vesting {
set_management_role(admin, contract_address, utf8(ROLE_BENEFICIARY_RESETTER), beneficiary_resetter);
}

/// Set the beneficiary for the operator.
public entry fun set_beneficiary_for_operator(
operator: &signer,
new_beneficiary: address,
) {
staking_contract::set_beneficiary_for_operator(operator, new_beneficiary);
}

public fun get_role_holder(contract_address: address, role: String): address acquires VestingAccountManagement {
assert!(exists<VestingAccountManagement>(contract_address), error::not_found(EVESTING_ACCOUNT_HAS_NO_ROLES));
let roles = &borrow_global<VestingAccountManagement>(contract_address).roles;
Expand Down Expand Up @@ -1012,7 +1020,13 @@ module aptos_framework::vesting {
const VALIDATOR_STATUS_INACTIVE: u64 = 4;

#[test_only]
public entry fun setup(aptos_framework: &signer, accounts: &vector<address>) {
const MODULE_EVENT: u64 = 26;

#[test_only]
const OPERATOR_BENEFICIARY_CHANGE: u64 = 39;

#[test_only]
public fun setup(aptos_framework: &signer, accounts: &vector<address>) {
use aptos_framework::aptos_account::create_account;

stake::initialize_for_test_custom(aptos_framework, MIN_STAKE, GRANT_AMOUNT * 10, 3600, true, 10, 10000, 1000000);
Expand All @@ -1023,6 +1037,8 @@ module aptos_framework::vesting {
create_account(addr);
};
});

std::features::change_feature_flags(aptos_framework, vector[MODULE_EVENT, OPERATOR_BENEFICIARY_CHANGE], vector[]);
}

#[test_only]
Expand Down Expand Up @@ -1534,6 +1550,85 @@ module aptos_framework::vesting {
assert!(coin::balance<AptosCoin>(operator_address) == expected_commission, 1);
}

#[test(aptos_framework = @0x1, admin = @0x123, shareholder = @0x234, operator1 = @0x345, beneficiary = @0x456, operator2 = @0x567)]
public entry fun test_set_beneficiary_for_operator(
aptos_framework: &signer,
admin: &signer,
shareholder: &signer,
operator1: &signer,
beneficiary: &signer,
operator2: &signer,
) acquires AdminStore, VestingContract {
let admin_address = signer::address_of(admin);
let operator_address1 = signer::address_of(operator1);
let operator_address2 = signer::address_of(operator2);
let shareholder_address = signer::address_of(shareholder);
let beneficiary_address = signer::address_of(beneficiary);
setup(aptos_framework, &vector[admin_address, shareholder_address, operator_address1, beneficiary_address]);
let contract_address = setup_vesting_contract(
admin, &vector[shareholder_address], &vector[GRANT_AMOUNT], admin_address, 0);
assert!(operator_commission_percentage(contract_address) == 0, 0);
let stake_pool_address = stake_pool_address(contract_address);
// 10% commission will be paid to the operator.
update_operator(admin, contract_address, operator_address1, 10);
assert!(staking_contract::beneficiary_for_operator(operator_address1) == operator_address1, 0);
set_beneficiary_for_operator(operator1, beneficiary_address);
assert!(staking_contract::beneficiary_for_operator(operator_address1) == beneficiary_address, 0);

// Operator needs to join the validator set for the stake pool to earn rewards.
let (_sk, pk, pop) = stake::generate_identity();
stake::join_validator_set_for_test(&pk, &pop, operator1, stake_pool_address, true);
stake::assert_stake_pool(stake_pool_address, GRANT_AMOUNT, 0, 0, 0);
assert!(get_accumulated_rewards(contract_address) == 0, 0);
assert!(remaining_grant(contract_address) == GRANT_AMOUNT, 0);

// Stake pool earns some rewards.
stake::end_epoch();
let (_, accumulated_rewards, _) = staking_contract::staking_contract_amounts(contract_address,
operator_address1
);
// Commission is calculated using the previous commission percentage which is 10%.
let expected_commission = accumulated_rewards / 10;

// Request commission.
staking_contract::request_commission(operator1, contract_address, operator_address1);
// Unlocks the commission.
stake::fast_forward_to_unlock(stake_pool_address);
expected_commission = with_rewards(expected_commission);

// Distribute the commission to the operator.
distribute(contract_address);

// Assert that the beneficiary receives the expected commission.
assert!(coin::balance<AptosCoin>(operator_address1) == 0, 1);
assert!(coin::balance<AptosCoin>(beneficiary_address) == expected_commission, 1);
let old_beneficiay_balance = coin::balance<AptosCoin>(beneficiary_address);

// switch operator to operator2. The rewards should go to operator2 not to the beneficiay of operator1.
update_operator(admin, contract_address, operator_address2, 10);

stake::end_epoch();
let (_, accumulated_rewards, _) = staking_contract::staking_contract_amounts(contract_address,
operator_address2
);

let expected_commission = accumulated_rewards / 10;

// Request commission.
staking_contract::request_commission(operator2, contract_address, operator_address2);
// Unlocks the commission.
stake::fast_forward_to_unlock(stake_pool_address);
expected_commission = with_rewards(expected_commission);

// Distribute the commission to the operator.
distribute(contract_address);

// Assert that the rewards go to operator2, and the balance of the operator1's beneficiay remains the same.
assert!(coin::balance<AptosCoin>(operator_address2) >= expected_commission, 1);
assert!(coin::balance<AptosCoin>(beneficiary_address) == old_beneficiay_balance, 1);

}

#[test(aptos_framework = @0x1, admin = @0x123, shareholder = @0x234)]
#[expected_failure(abort_code = 0x30008, location = Self)]
public entry fun test_cannot_unlock_rewards_after_contract_is_terminated(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,14 @@ spec aptos_framework::vesting {
include SetManagementRoleAbortsIf;
}

spec set_beneficiary_for_operator(
operator: &signer,
new_beneficiary: address,
) {
// TODO: temporary mockup
pragma verify = false;
}

spec get_role_holder(contract_address: address, role: String): address {
aborts_if !exists<VestingAccountManagement>(contract_address);
let roles = global<VestingAccountManagement>(contract_address).roles;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ module aptos_framework::delegation_pool_integration_tests {
#[test_only]
const DELEGATION_POOLS: u64 = 11;

#[test_only]
const MODULE_EVENT: u64 = 26;

#[test_only]
public fun initialize_for_test(aptos_framework: &signer) {
initialize_for_test_custom(
Expand Down Expand Up @@ -76,7 +79,7 @@ module aptos_framework::delegation_pool_integration_tests {
voting_power_increase_limit
);
reconfiguration::initialize_for_test(aptos_framework);
features::change_feature_flags(aptos_framework, vector[DELEGATION_POOLS], vector[]);
features::change_feature_flags(aptos_framework, vector[DELEGATION_POOLS, MODULE_EVENT], vector[]);
}

#[test_only]
Expand Down
Loading

0 comments on commit 8beaf59

Please sign in to comment.