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

Generalize governance to stake changes subscriber #98

Merged
merged 2 commits into from
Nov 10, 2024
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
4 changes: 2 additions & 2 deletions contracts/interfaces/ISFC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ interface ISFC {

function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external;

function updateVoteBookAddress(address v) external;
function updateStakeSubscriberAddress(address v) external;

function voteBookAddress() external view returns (address);
function stakeSubscriberAddress() external view returns (address);

function setRedirectionAuthorizer(address v) external;

Expand Down
48 changes: 18 additions & 30 deletions contracts/sfc/SFC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ contract SFC is Initializable, Ownable, Version {

ConstantsManager internal c;

// the governance contract (to recalculate votes when the stake changes)
address public voteBookAddress;
// the contract subscribed to stake changes notifications
address public stakeSubscriberAddress;

// address derived from the validator pubkey => validator id
mapping(address pubkeyAddress => uint256 validatorID) public pubkeyAddressToValidatorID;
Expand Down Expand Up @@ -161,8 +161,8 @@ contract SFC is Initializable, Ownable, Version {
error TransfersNotAllowed();
error TransferFailed();

// governance
error GovVotesRecountFailed();
// stake changes subscriber
error StakeSubscriberFailed();

// staking
error InsufficientSelfStake();
Expand Down Expand Up @@ -369,18 +369,6 @@ contract SFC is Initializable, Ownable, Version {
emit UpdatedSlashingRefundRatio(validatorID, refundRatio);
}

/// Recount votes for a delegator and a validator.
/// Forces applying validators weights changes in governance voting.
function recountVotes(address delegator, address validatorAuth, bool strict, uint256 gas) external {
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = voteBookAddress.call{gas: gas}(
abi.encodeWithSignature("recountVotes(address,address)", delegator, validatorAuth)
);
if (!success && strict) {
revert GovVotesRecountFailed();
}
}

/// Delegate stake to a validator.
function delegate(uint256 toValidatorID) external payable {
_delegate(msg.sender, toValidatorID, msg.value);
Expand All @@ -402,7 +390,7 @@ contract SFC is Initializable, Ownable, Version {
_setValidatorDeactivated(validatorID, status);
_syncValidator(validatorID, false);
address validatorAddr = getValidator[validatorID].auth;
_recountVotes(validatorAddr, validatorAddr, false);
_notifyStakeSubscriber(validatorAddr, validatorAddr, false);
}

/// Stash rewards for a delegator.
Expand All @@ -428,8 +416,8 @@ contract SFC is Initializable, Ownable, Version {
}

/// Update voteBook address.
function updateVoteBookAddress(address v) external onlyOwner {
voteBookAddress = v;
function updateStakeSubscriberAddress(address v) external onlyOwner {
stakeSubscriberAddress = v;
}

/// Get consts address.
Expand Down Expand Up @@ -598,7 +586,7 @@ contract SFC is Initializable, Ownable, Version {

emit Delegated(delegator, toValidatorID, amount);

_recountVotes(delegator, getValidator[toValidatorID].auth, strict);
_notifyStakeSubscriber(delegator, getValidator[toValidatorID].auth, strict);
}

/// Un-delegate stake from a validator.
Expand Down Expand Up @@ -633,7 +621,7 @@ contract SFC is Initializable, Ownable, Version {
_setValidatorDeactivated(toValidatorID, WITHDRAWN_BIT);
}

_recountVotes(delegator, getValidator[toValidatorID].auth, strict);
_notifyStakeSubscriber(delegator, getValidator[toValidatorID].auth, strict);
}

/// Get slashing penalty for a stake.
Expand Down Expand Up @@ -975,18 +963,18 @@ contract SFC is Initializable, Ownable, Version {
totalSupply = totalSupply + amount;
}

/// Recount votes for a delegator and a validator.
/// Force applying validators weights changes in governance voting.
function _recountVotes(address delegator, address validatorAuth, bool strict) internal {
if (voteBookAddress != address(0)) {
// Don't allow recountVotes to use up all the gas
/// Notify stake subscriber about staking changes.
/// Used to recount votes from delegators in the governance contract.
function _notifyStakeSubscriber(address delegator, address validatorAuth, bool strict) internal {
if (stakeSubscriberAddress != address(0)) {
// Don't allow announceStakeChange to use up all the gas
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = voteBookAddress.call{gas: 8000000}(
abi.encodeWithSignature("recountVotes(address,address)", delegator, validatorAuth)
(bool success, ) = stakeSubscriberAddress.call{gas: 8000000}(
abi.encodeWithSignature("announceStakeChange(address,address)", delegator, validatorAuth)
);
// Don't revert if recountVotes failed unless strict mode enabled
// Don't revert if announceStakeChange failed unless strict mode enabled
if (!success && strict) {
revert GovVotesRecountFailed();
revert StakeSubscriberFailed();
}
}
}
Expand Down