Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Stake] Allow to set the beneficiary for operator #10455

Merged
merged 2 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ pub enum FeatureFlag {
AggregatorV2DelayedFields,
ConcurrentAssets,
LimitMaxIdentifierLength,
OperatorBeneficiaryChange,
}

fn generate_features_blob(writer: &CodeWriter, data: &[u64]) {
Expand Down Expand Up @@ -232,6 +233,7 @@ impl From<FeatureFlag> for AptosFeatureFlag {
},
FeatureFlag::ConcurrentAssets => AptosFeatureFlag::CONCURRENT_ASSETS,
FeatureFlag::LimitMaxIdentifierLength => AptosFeatureFlag::LIMIT_MAX_IDENTIFIER_LENGTH,
FeatureFlag::OperatorBeneficiaryChange => AptosFeatureFlag::OPERATOR_BENEFICIARY_CHANGE,
}
}
}
Expand Down Expand Up @@ -298,6 +300,7 @@ impl From<AptosFeatureFlag> for FeatureFlag {
},
AptosFeatureFlag::CONCURRENT_ASSETS => FeatureFlag::ConcurrentAssets,
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.

407 changes: 392 additions & 15 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 @@ -243,6 +243,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
95 changes: 95 additions & 0 deletions 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 @@ -1011,6 +1019,12 @@ module aptos_framework::vesting {
#[test_only]
const VALIDATOR_STATUS_INACTIVE: u64 = 4;

#[test_only]
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;
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
Loading