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

feat: add agent address for validators #568

Merged
merged 5 commits into from
Jul 17, 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
56 changes: 47 additions & 9 deletions contracts/BC_fusion/StakeHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ contract StakeHub is System, Initializable, Protectable {
error ConsensusAddressExpired();
// @notice signature: 0x0d7b78d4
error InvalidSynPackage();
// @notice signature: 0xbebdc757
error InvalidAgent();
// @notice signature: 0x682a6e7c
error InvalidValidator();

/*----------------- storage -----------------*/
uint8 private _receiveFundStatus;
Expand Down Expand Up @@ -135,6 +139,9 @@ contract StakeHub is System, Initializable, Protectable {
// slash key => slash jail time
mapping(bytes32 => uint256) private _felonyRecords;

// agent => validator operator address
mapping(address => address) public agentToOperator;

/*----------------- structs and events -----------------*/
struct StakeMigrationPackage {
address operatorAddress; // the operator address of the target validator to delegate to
Expand Down Expand Up @@ -162,7 +169,9 @@ contract StakeHub is System, Initializable, Protectable {
bool jailed;
uint256 jailUntil;
uint256 updateTime;
uint256[20] __reservedSlots;
// The agent can perform transactions on behalf of the operatorAddress in certain scenarios.
address agent;
uint256[19] __reservedSlots;
}

struct Description {
Expand Down Expand Up @@ -219,6 +228,7 @@ contract StakeHub is System, Initializable, Protectable {
address indexed operatorAddress, address indexed delegator, uint256 bnbAmount, StakeMigrationRespCode respCode
);
event UnexpectedPackage(uint8 channelId, bytes msgBytes);
event AgentChanged(address indexed operatorAddress, address indexed oldAgent, address indexed newAgent);

/*----------------- modifiers -----------------*/
modifier validatorExist(address operatorAddress) {
Expand Down Expand Up @@ -315,6 +325,24 @@ contract StakeHub is System, Initializable, Protectable {
}

/*----------------- external functions -----------------*/
function updateAgent(address newAgent) external validatorExist(msg.sender) {
if (agentToOperator[newAgent] != address(0)) revert InvalidAgent();
if (_validatorSet.contains(newAgent)) revert InvalidAgent();

address operatorAddress = msg.sender;
address oldAgent = _validators[operatorAddress].agent;
if (oldAgent == newAgent) revert InvalidAgent();

if (oldAgent != address(0)) {
delete agentToOperator[oldAgent];
}

_validators[operatorAddress].agent = newAgent;
agentToOperator[newAgent] = operatorAddress;

emit AgentChanged(operatorAddress, oldAgent, newAgent);
}

/**
* @param consensusAddress the consensus address of the validator
* @param voteAddress the vote address of the validator
Expand All @@ -332,6 +360,8 @@ contract StakeHub is System, Initializable, Protectable {
// basic check
address operatorAddress = msg.sender;
if (_validatorSet.contains(operatorAddress)) revert ValidatorExisted();
if (agentToOperator[operatorAddress] != address(0)) revert InvalidValidator();
unclezoro marked this conversation as resolved.
Show resolved Hide resolved

if (consensusToOperator[consensusAddress] != address(0) || _legacyConsensusAddress[consensusAddress]) {
revert DuplicateConsensusAddress();
}
Expand Down Expand Up @@ -384,14 +414,14 @@ contract StakeHub is System, Initializable, Protectable {
external
whenNotPaused
notInBlackList
validatorExist(msg.sender)
validatorExist(_bep410MsgSender())
{
if (newConsensusAddress == address(0)) revert InvalidConsensusAddress();
if (consensusToOperator[newConsensusAddress] != address(0) || _legacyConsensusAddress[newConsensusAddress]) {
revert DuplicateConsensusAddress();
}

address operatorAddress = msg.sender;
address operatorAddress = _bep410MsgSender();
Validator storage valInfo = _validators[operatorAddress];
if (valInfo.updateTime + BREATHE_BLOCK_INTERVAL > block.timestamp) revert UpdateTooFrequently();

Expand All @@ -410,9 +440,9 @@ contract StakeHub is System, Initializable, Protectable {
external
whenNotPaused
notInBlackList
validatorExist(msg.sender)
validatorExist(_bep410MsgSender())
{
address operatorAddress = msg.sender;
address operatorAddress = _bep410MsgSender();
Validator storage valInfo = _validators[operatorAddress];
if (valInfo.updateTime + BREATHE_BLOCK_INTERVAL > block.timestamp) revert UpdateTooFrequently();

Expand All @@ -436,9 +466,9 @@ contract StakeHub is System, Initializable, Protectable {
external
whenNotPaused
notInBlackList
validatorExist(msg.sender)
validatorExist(_bep410MsgSender())
{
address operatorAddress = msg.sender;
address operatorAddress = _bep410MsgSender();
Validator storage valInfo = _validators[operatorAddress];
if (valInfo.updateTime + BREATHE_BLOCK_INTERVAL > block.timestamp) revert UpdateTooFrequently();

Expand All @@ -456,9 +486,9 @@ contract StakeHub is System, Initializable, Protectable {
function editVoteAddress(
bytes calldata newVoteAddress,
bytes calldata blsProof
) external whenNotPaused notInBlackList validatorExist(msg.sender) {
) external whenNotPaused notInBlackList validatorExist(_bep410MsgSender()) {
// proof-of-possession verify
address operatorAddress = msg.sender;
address operatorAddress = _bep410MsgSender();
if (!_checkVoteAddress(operatorAddress, newVoteAddress, blsProof)) revert InvalidVoteAddress();
if (voteToOperator[newVoteAddress] != address(0) || _legacyVoteAddress[newVoteAddress]) {
revert DuplicateVoteAddress();
Expand Down Expand Up @@ -1179,4 +1209,12 @@ contract StakeHub is System, Initializable, Protectable {
uint256 bnbAmount = IStakeCredit(_validators[operatorAddress].creditContract).claim(msg.sender, requestNumber);
emit Claimed(operatorAddress, msg.sender, bnbAmount);
}

function _bep410MsgSender() internal view returns (address) {
if (agentToOperator[msg.sender] != address(0)) {
return agentToOperator[msg.sender];
}

return msg.sender;
}
}
70 changes: 70 additions & 0 deletions test/StakeHub.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ contract StakeHubTest is Deployer {
event MigrateFailed(
address indexed operatorAddress, address indexed delegator, uint256 bnbAmount, StakeMigrationRespCode respCode
);
event AgentChanged(address indexed operatorAddress, address indexed oldAgent, address indexed newAgent);

enum StakeMigrationRespCode {
MIGRATE_SUCCESS,
Expand Down Expand Up @@ -726,4 +727,73 @@ contract StakeHubTest is Deployer {
elements[1] = vals.encodeList();
return elements.encodeList();
}

function testAgent() external {
// create validator
(address validator,,,) = _createValidator(2000 ether);
vm.startPrank(validator);

// edit failed because of `UpdateTooFrequently`
vm.expectRevert(StakeHub.UpdateTooFrequently.selector);
stakeHub.editConsensusAddress(address(1));

// update agent
address newAgent = validator;
vm.expectRevert(StakeHub.InvalidAgent.selector);
stakeHub.updateAgent(newAgent);

newAgent = address(0x1234);
vm.expectEmit(true, true, false, true, address(stakeHub));
emit AgentChanged(validator, address(0), newAgent);
stakeHub.updateAgent(newAgent);

vm.stopPrank();

vm.startPrank(newAgent);
// edit consensus address
vm.warp(block.timestamp + 1 days);
address newConsensusAddress = address(0x1234);
vm.expectEmit(true, true, false, true, address(stakeHub));
emit ConsensusAddressEdited(validator, newConsensusAddress);
stakeHub.editConsensusAddress(newConsensusAddress);
address realConsensusAddr = stakeHub.getValidatorConsensusAddress(validator);
assertEq(realConsensusAddr, newConsensusAddress);

// edit commission rate
vm.warp(block.timestamp + 1 days);
vm.expectRevert(StakeHub.InvalidCommission.selector);
stakeHub.editCommissionRate(110);
vm.expectRevert(StakeHub.InvalidCommission.selector);
stakeHub.editCommissionRate(16);
vm.expectEmit(true, false, false, true, address(stakeHub));
emit CommissionRateEdited(validator, 15);
stakeHub.editCommissionRate(15);
StakeHub.Commission memory realComm = stakeHub.getValidatorCommission(validator);
assertEq(realComm.rate, 15);

// edit description
vm.warp(block.timestamp + 1 days);
StakeHub.Description memory description = stakeHub.getValidatorDescription(validator);
description.moniker = "Test";
description.website = "Test";
vm.expectEmit(true, false, false, true, address(stakeHub));
emit DescriptionEdited(validator);
stakeHub.editDescription(description);
StakeHub.Description memory realDesc = stakeHub.getValidatorDescription(validator);
assertNotEq(realDesc.moniker, "Test"); // edit moniker will be ignored
assertEq(realDesc.website, "Test");

// edit vote address
vm.warp(block.timestamp + 1 days);
bytes memory newVoteAddress =
hex"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234";
bytes memory blsProof = new bytes(96);
vm.expectEmit(true, false, false, true, address(stakeHub));
emit VoteAddressEdited(validator, newVoteAddress);
stakeHub.editVoteAddress(newVoteAddress, blsProof);
bytes memory realVoteAddr = stakeHub.getValidatorVoteAddress(validator);
assertEq(realVoteAddr, newVoteAddress);

vm.stopPrank();
}
}
6 changes: 6 additions & 0 deletions test/utils/interface/IStakeHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ interface StakeHub {
error ValidatorNotJailed();
error VoteAddressExpired();
error ZeroShares();
error InvalidAgent();
error InvalidValidator();

event BlackListed(address indexed target);
event Claimed(address indexed operatorAddress, address indexed delegator, uint256 bnbAmount);
Expand Down Expand Up @@ -94,6 +96,7 @@ interface StakeHub {
);
event ValidatorUnjailed(address indexed operatorAddress);
event VoteAddressEdited(address indexed operatorAddress, bytes newVoteAddress);
event AgentChanged(address indexed operatorAddress, address indexed oldAgent, address indexed newAgent);

receive() external payable;

Expand Down Expand Up @@ -179,4 +182,7 @@ interface StakeHub {
function updateParam(string memory key, bytes memory value) external;
function voteExpiration(bytes memory) external view returns (uint256);
function voteToOperator(bytes memory) external view returns (address);

function agentToOperator(address) external view returns (address);
function updateAgent(address newAgent) external;
}
Loading