Validators that are not in the committee can't unbond delegators that are pre bonded to them
Summary
Validators that are not in the committee can't unbond delegators that are pre bonded to them because the caller authorization in the unbond_public function will always be false due validators that aren't in the committee yet won't have a withdraw address set.
Vulnerability Detail
In the unbond_public function the caller is allowed to unbond for the staker when:
r7: caller == staker's withdraw address.
OR
r11: caller == validator's withdraw address(r10) AND validator should have set the withdraw address(r8).
The problem lies in that the validator's withdraw address is only set when he calls the bond_validator function, has 10mil or more credits delegated to him and he is a new validator in the committee. That process is valid but it results in if the validator never was in the committee(like not having 10mil credits delegated to him) that he doesn't have a withdraw address set.
So the validator that isn't in the committee but has pre bonded stakers can't unbond them because in the unbond_public function:
r7 will be false if the withdraw address of the staker isnt the validator that is calling.
AND
r11 will be false because the validator will never have set a withdraw address(r8).
Both conditions being false results in a revert:
// Either the caller is the staker's withdrawal address OR the validator's withdrawal address is set to the caller.
or r7 r11 into r12;
// Enforce the permission as `true`.
assert.eq r12 true;
Impact
The intended functionality that allows a validator to unbond delegators even when the validator is not in the committee does not work.
Stated that a validator should be able to unbond delegators even when the validator is not in the committee:
// Check if the validator's withdrawal address has been set.
// Note: This contains check must use `withdraw` and **not** `committee` to ensure the validator
// can unbond delegators even when the validator is not in the committee. Of course, if the validator is
// in the committee, then the validator must be able to unbond its delegators.
// Validators are permitted to fully unbond any of their delegators. When a validator unbonds a delegator,
// the entire bonded balance is unbonded, regardless of the amount of microcredits and may end up removing the validator
// from the committee if the total delegated balance falls below 10M credits.
morbsel
Medium
Validators that are not in the committee can't unbond delegators that are pre bonded to them
Summary
Validators that are not in the committee can't unbond delegators that are pre bonded to them because the caller authorization in the
unbond_public
function will always be false due validators that aren't in the committee yet won't have a withdraw address set.Vulnerability Detail
In the
unbond_public
function the caller is allowed to unbond for the staker when:r7
: caller == staker's withdraw address. ORr11
: caller == validator's withdraw address(r10
) AND validator should have set the withdraw address(r8
).The problem lies in that the validator's withdraw address is only set when he calls the
bond_validator
function, has 10mil or more credits delegated to him and he is a new validator in the committee. That process is valid but it results in if the validator never was in the committee(like not having 10mil credits delegated to him) that he doesn't have a withdraw address set.So the validator that isn't in the committee but has pre bonded stakers can't unbond them because in the
unbond_public
function:r7
will be false if the withdraw address of the staker isnt the validator that is calling. ANDr11
will be false because the validator will never have set a withdraw address(r8
).Both conditions being false results in a revert:
Impact
The intended functionality that allows a validator to unbond delegators even when the validator is not in the committee does not work.
Code Snippet
Caller authorization in
unbond_public
function: https://github.com/sherlock-audit/2024-05-aleo/blob/55b2e4a02f27602a54c11f964f6f610fee6f4ab8/snarkVM/synthesizer/program/src/resources/credits.aleo#L448-L470Setting withdraw address for new validators in
bond_validator
function: https://github.com/sherlock-audit/2024-05-aleo/blob/55b2e4a02f27602a54c11f964f6f610fee6f4ab8/snarkVM/synthesizer/program/src/resources/credits.aleo#L245-L251Stated that a validator should be able to unbond delegators even when the validator is not in the committee:
at https://github.com/sherlock-audit/2024-05-aleo/blob/55b2e4a02f27602a54c11f964f6f610fee6f4ab8/snarkVM/synthesizer/program/src/resources/credits.aleo#L455-L458
and:
at https://github.com/sherlock-audit/2024-05-aleo/blob/55b2e4a02f27602a54c11f964f6f610fee6f4ab8/snarkVM/synthesizer/program/src/resources/credits.aleo#L415-L417
Tool used
Manual Review
Recommendation
Possibilities:
set_withdraw_address
function to allow validators/users to set/change a withdraw addressDuplicate of #20