Skip to content

Commit

Permalink
chore: add view function and update annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonberg1997 committed Dec 21, 2023
1 parent e077181 commit a9e5db1
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 34 deletions.
12 changes: 6 additions & 6 deletions abi/bscvalidatorset.abi
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,26 @@
},
{
"type": "function",
"name": "BURN_ADDRESS",
"name": "BLOCK_FEES_RATIO_SCALE",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "BLOCK_FEES_RATIO_SCALE",
"name": "BURN_ADDRESS",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
Expand Down
34 changes: 34 additions & 0 deletions abi/stakehub.abi
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,40 @@
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getValidators",
"inputs": [
{
"name": "offset",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "limit",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "operatorAddrs",
"type": "address[]",
"internalType": "address[]"
},
{
"name": "creditAddrs",
"type": "address[]",
"internalType": "address[]"
},
{
"name": "totalLength",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "initialize",
Expand Down
46 changes: 39 additions & 7 deletions contracts/BC_fusion/StakeHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ contract StakeHub is System, Initializable {
function initialize() external initializer onlyCoinbase onlyZeroGasPrice {
transferGasLimit = 5000;
minSelfDelegationBNB = 2_000 ether;
minDelegationBNBChange = 1 ether;
minDelegationBNBChange = 1 ether - 1; // minus 1 to be more user-friendly when precision loss happens
maxElectedValidators = 29;
unbondPeriod = 7 days;
redelegateFeeRate = 2;
Expand Down Expand Up @@ -314,6 +314,7 @@ contract StakeHub is System, Initializable {
voteToOperator[voteAddress] = operatorAddress;

emit ValidatorCreated(consensusAddress, operatorAddress, creditContract, voteAddress);
emit Delegated(operatorAddress, operatorAddress, delegation, delegation);

IGovToken(GOV_TOKEN_ADDR).sync(creditContract, operatorAddress);
}
Expand Down Expand Up @@ -780,7 +781,7 @@ contract StakeHub is System, Initializable {

/*----------------- view functions -----------------*/
/**
* @return is the system paused
* @return whether the system is paused
*/
function isPaused() external view returns (bool) {
return _paused;
Expand All @@ -802,9 +803,39 @@ contract StakeHub is System, Initializable {
return IStakeCredit(_validators[operatorAddress].creditContract).totalPooledBNBRecord(index);
}

/**
* @notice pagination query all validators' operator address and credit contract address
* @return operatorAddrs operator addresses
* @return creditAddrs credit contract addresses
* @return totalLength total number of validators
*/
function getValidators(
uint256 offset,
uint256 limit
) external view returns (address[] memory operatorAddrs, address[] memory creditAddrs, uint256 totalLength) {
totalLength = _validatorSet.length();
if (offset >= totalLength) {
return (operatorAddrs, creditAddrs, totalLength);
}

limit = limit == 0 ? totalLength : limit;
uint256 count = (totalLength - offset) > limit ? limit : (totalLength - offset);
operatorAddrs = new address[](count);
creditAddrs = new address[](count);
for (uint256 i; i < count; ++i) {
operatorAddrs[i] = _validatorSet.at(offset + i);
creditAddrs[i] = _validators[operatorAddrs[i]].creditContract;
}
}

/**
* @notice get the basic info of a validator
* including consensus address, credit contract, created time, vote address, jailed and jailUntil
* @return consensusAddress the consensus address of the validator
* @return creditContract the credit contract address of the validator
* @return createdTime the creation time of the validator
* @return voteAddress the vote address of the validator
* @return jailed whether the validator is jailed
* @return jailUntil the jail time of the validator
*/
function getValidatorBasicInfo(address operatorAddress)
external
Expand Down Expand Up @@ -853,11 +884,12 @@ contract StakeHub is System, Initializable {
}

/**
* @dev this function will be invoked by Parlia consensus engine.
* @dev this function will be used by Parlia consensus engine.
* @notice get the election info of a validator
* including consensus address, voting power and vote address.
* The voting power will be 0 if the validator is jailed.
* This function is for the consensus engine.
* @return consensusAddrs the consensus addresses of the validators
* @return votingPowers the voting powers of the validators. The voting power will be 0 if the validator is jailed.
* @return voteAddrs the vote addresses of the validators
* @return totalLength the total number of validators
*/
function getValidatorElectionInfo(
uint256 offset,
Expand Down
41 changes: 21 additions & 20 deletions test/StakeHub.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ contract StakeHubTest is Deployer {
(address validator,) = _createValidator(2000 ether);
(address consensusAddress,,, bytes memory voteAddress,,) = stakeHub.getValidatorBasicInfo(validator);

address operatorAddress = _getNextUserAddress();
vm.startPrank(operatorAddress);

// create failed with duplicate consensus address
uint256 delegation = 2000 ether;
address operatorAddress = _getNextUserAddress();
uint256 toLock = stakeHub.LOCK_AMOUNT();
StakeHub.Commission memory commission = StakeHub.Commission({ rate: 10, maxRate: 100, maxChangeRate: 5 });
StakeHub.Description memory description = StakeHub.Description({
moniker: string.concat("T", vm.toString(uint24(uint160(operatorAddress)))),
Expand All @@ -55,27 +58,23 @@ contract StakeHubTest is Deployer {
);
bytes memory blsProof = new bytes(96);

uint256 toLock = stakeHub.LOCK_AMOUNT();
vm.prank(operatorAddress);
vm.expectRevert();
vm.expectRevert(StakeHub.DuplicateConsensusAddress.selector);
stakeHub.createValidator{ value: delegation + toLock }(
consensusAddress, blsPubKey, blsProof, commission, description
);

// create failed with duplicate vote address
consensusAddress = address(uint160(uint256(keccak256(blsPubKey))));
vm.prank(operatorAddress);
vm.expectRevert();
vm.expectRevert(StakeHub.DuplicateVoteAddress.selector);
stakeHub.createValidator{ value: delegation + toLock }(
consensusAddress, voteAddress, blsProof, commission, description
);

// create failed with duplicate moniker
description = stakeHub.getValidatorDescription(validator);
vm.prank(operatorAddress);
vm.expectRevert();
vm.expectRevert(StakeHub.DuplicateMoniker.selector);
stakeHub.createValidator{ value: delegation + toLock }(
consensusAddress, voteAddress, blsProof, commission, description
consensusAddress, blsPubKey, blsProof, commission, description
);
}

Expand All @@ -85,7 +84,7 @@ contract StakeHubTest is Deployer {
vm.startPrank(validator);

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

// edit consensus address
Expand All @@ -99,9 +98,9 @@ contract StakeHubTest is Deployer {

// edit commission rate
vm.warp(block.timestamp + 1 days);
vm.expectRevert();
vm.expectRevert(StakeHub.InvalidCommission.selector);
stakeHub.editCommissionRate(110);
vm.expectRevert();
vm.expectRevert(StakeHub.InvalidCommission.selector);
stakeHub.editCommissionRate(16);
vm.expectEmit(true, false, false, true, address(stakeHub));
emit CommissionRateEdited(validator, 15);
Expand Down Expand Up @@ -141,14 +140,16 @@ contract StakeHubTest is Deployer {
vm.startPrank(delegator);

// failed with too small delegation amount
vm.expectRevert();
vm.expectRevert(StakeHub.DelegationAmountTooSmall.selector);
stakeHub.delegate{ value: 1 }(validator, false);

// success case
uint256 bnbAmount = 100 ether;
stakeHub.delegate{ value: bnbAmount }(validator, false);
uint256 shares = IStakeCredit(credit).balanceOf(delegator);
assertEq(shares, bnbAmount);
uint256 pooledBNB = IStakeCredit(credit).getPooledBNBByShares(shares);
assertEq(pooledBNB, bnbAmount);

vm.stopPrank();
}
Expand All @@ -163,14 +164,14 @@ contract StakeHubTest is Deployer {
uint256 shares = IStakeCredit(credit).balanceOf(delegator);

// failed with not enough shares
vm.expectRevert();
vm.expectRevert(StakeCredit.InsufficientBalance.selector);
stakeHub.undelegate(validator, shares + 1);

// success case
stakeHub.undelegate(validator, shares / 2);

// claim failed
vm.expectRevert();
vm.expectRevert(StakeCredit.NoClaimableUnbondRequest.selector);
stakeHub.claim(validator, 0);

// claim success
Expand Down Expand Up @@ -224,11 +225,11 @@ contract StakeHubTest is Deployer {
uint256 oldShares = IStakeCredit(credit1).balanceOf(delegator);

// failed with too small redelegation amount
vm.expectRevert();
vm.expectRevert(StakeHub.DelegationAmountTooSmall.selector);
stakeHub.redelegate(validator1, validator2, 1, false);

// failed with not enough shares
vm.expectRevert();
vm.expectRevert(StakeCredit.InsufficientBalance.selector);
stakeHub.redelegate(validator1, validator2, oldShares + 1, false);

// success case
Expand All @@ -243,10 +244,10 @@ contract StakeHubTest is Deployer {

vm.stopPrank();

// self redelegate
vm.startPrank(validator1);
// self redelegate failed because of `SelfDelegationNotEnough`
uint256 selfDelegation = 2000 ether;
vm.expectRevert();
vm.expectRevert(StakeHub.SelfDelegationNotEnough.selector);
vm.prank(validator1);
stakeHub.redelegate(validator1, validator2, selfDelegation, false);
}

Expand Down
2 changes: 1 addition & 1 deletion test/utils/interface/IBSCValidatorSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ interface BSCValidatorSet {
receive() external payable;

function BIND_CHANNELID() external view returns (uint8);
function BURN_ADDRESS() external view returns (address);
function BLOCK_FEES_RATIO_SCALE() external view returns (uint256);
function BURN_ADDRESS() external view returns (address);
function CODE_OK() external view returns (uint32);
function CROSS_CHAIN_CONTRACT_ADDR() external view returns (address);
function CROSS_STAKE_CHANNELID() external view returns (uint8);
Expand Down
4 changes: 4 additions & 0 deletions test/utils/interface/IStakeHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ interface StakeHub {
);
function getValidatorRewardRecord(address operatorAddress, uint256 index) external view returns (uint256);
function getValidatorTotalPooledBNBRecord(address operatorAddress, uint256 index) external view returns (uint256);
function getValidators(uint256 offset, uint256 limit)
external
view
returns (address[] memory operatorAddrs, address[] memory creditAddrs, uint256 totalLength);
function initialize() external;
function isPaused() external view returns (bool);
function maliciousVoteSlash(bytes memory voteAddress) external;
Expand Down

0 comments on commit a9e5db1

Please sign in to comment.