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

Fix undelegate from deprecated candidates issue #41

Merged
merged 1 commit into from
Nov 1, 2022
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
14 changes: 7 additions & 7 deletions contracts/interfaces/IStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ interface IStaking is IRewardPool {
/// @dev Emitted when the staked amount is deprecated.
event StakedAmountDeprecated(address indexed validator, address indexed admin, uint256 amount);
/// @dev Emitted when the pool admin staked for themself.
event Staked(address indexed validator, uint256 amount);
event Staked(address indexed consensuAddr, uint256 amount);
/// @dev Emitted when the pool admin unstaked the amount of RON from themself.
event Unstaked(address indexed validator, uint256 amount);
/// @dev Emitted when the delegator staked for a validator.
event Delegated(address indexed delegator, address indexed validator, uint256 amount);
/// @dev Emitted when the delegator unstaked from a validator.
event Undelegated(address indexed delegator, address indexed validator, uint256 amount);
event Unstaked(address indexed consensuAddr, uint256 amount);
/// @dev Emitted when the delegator staked for a validator candidate.
event Delegated(address indexed delegator, address indexed consensuAddr, uint256 amount);
/// @dev Emitted when the delegator unstaked from a validator candidate.
event Undelegated(address indexed delegator, address indexed consensuAddr, uint256 amount);
/// @dev Emitted when the minimum balance for being a validator is updated.
event MinValidatorBalanceUpdated(uint256 threshold);

Expand Down Expand Up @@ -176,7 +176,7 @@ interface IStaking is IRewardPool {
* - The method caller is the pool admin.
*
*/
function requestRenounce(address consensusAddr) external;
function requestRenounce(address _consensusAddr) external;

///////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS FOR DELEGATOR //
Expand Down
2 changes: 1 addition & 1 deletion contracts/ronin/staking/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ contract Staking is IStaking, StakingManager, Initializable {
}
}

delete _stakingPool[_pool.addr];
delete _stakingPool[_pool.addr].stakedAmount;
}

emit PoolsDeprecated(_pools);
Expand Down
73 changes: 66 additions & 7 deletions test/staking/Staking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ describe('Staking test', () => {
tx = await stakingContract.connect(poolAddr).unstake(poolAddr.address, 1);
await expect(tx!).emit(stakingContract, 'Unstaked').withArgs(poolAddr.address, 1);
expect(await stakingContract.totalBalance(poolAddr.address)).eq(minValidatorBalance.mul(2));
expect(await stakingContract.balanceOf(poolAddr.address, poolAddr.address)).eq(minValidatorBalance.mul(2));
});

it('[Delegator] Should be able to delegate/undelegate to a validator candidate', async () => {
await stakingContract.delegate(poolAddr.address, { value: 10 });
expect(await stakingContract.balanceOf(poolAddr.address, deployer.address)).eq(10);
await stakingContract.undelegate(poolAddr.address, 1);
expect(await stakingContract.balanceOf(poolAddr.address, deployer.address)).eq(9);
});

it('Should be not able to unstake with the balance left is not larger than the minimum balance threshold', async () => {
Expand Down Expand Up @@ -145,7 +153,7 @@ describe('Staking test', () => {
expect(await stakingContract.getStakingPool(poolAddr.address)).eql([
poolAddr.address,
stakedAmount,
stakedAmount,
stakedAmount.add(9),
]);
await expect(() => validatorContract.wrapUpEpoch()).changeEtherBalance(poolAddr, stakedAmount);
await expect(stakingContract.getStakingPool(poolAddr.address)).revertedWith(
Expand All @@ -159,6 +167,17 @@ describe('Staking test', () => {
otherPoolAddr = validatorCandidates[2];
});

it('Should be able to undelegate from a deprecated validator candidate', async () => {
await stakingContract.undelegate(poolAddr.address, 1);
expect(await stakingContract.balanceOf(poolAddr.address, deployer.address)).eq(8);
});

it('Should not be able to delegate to a deprecated pool', async () => {
await expect(stakingContract.delegate(poolAddr.address, { value: 1 })).revertedWith(
'StakingManager: query for non-existent pool'
);
});

it('Should not be able to delegate with empty value', async () => {
await expect(stakingContract.delegate(otherPoolAddr.address)).revertedWith(
'StakingManager: query with empty value'
Expand All @@ -174,12 +193,6 @@ describe('Staking test', () => {
);
});

it('Should not be able to delegate to a deprecated pool', async () => {
await expect(stakingContract.delegate(poolAddr.address, { value: 1 })).revertedWith(
'StakingManager: query for non-existent pool'
);
});

it('Should be able to delegate/undelegate', async () => {
let tx: ContractTransaction;
tx = await stakingContract.connect(userA).delegate(otherPoolAddr.address, { value: 1 });
Expand All @@ -194,5 +207,51 @@ describe('Staking test', () => {
await expect(tx!).emit(stakingContract, 'Undelegated').withArgs(userA.address, otherPoolAddr.address, 1);
expect(await stakingContract.totalBalance(otherPoolAddr.address)).eq(minValidatorBalance.mul(2).add(1));
});

it('Should not be able to undelegate with empty amount', async () => {
await expect(stakingContract.undelegate(otherPoolAddr.address, 0)).revertedWith('StakingManager: invalid amount');
});

it('Should not be able to undelegate more than the delegated amount', async () => {
await expect(stakingContract.undelegate(otherPoolAddr.address, 1000)).revertedWith(
'StakingManager: insufficient amount to undelegate'
);
});

it('[Validator Candidate] Should an ex-candidate to rejoin Staking contract', async () => {
await stakingContract
.connect(poolAddr)
.applyValidatorCandidate(
poolAddr.address,
poolAddr.address,
poolAddr.address,
poolAddr.address,
2,
/* 0.02% */ { value: minValidatorBalance }
);
expect(await stakingContract.getStakingPool(poolAddr.address)).eql([
poolAddr.address,
minValidatorBalance,
minValidatorBalance.add(8),
]);
expect(await stakingContract.balanceOf(poolAddr.address, deployer.address)).eq(8);
});

it('Should be able to delegate/undelegate for the rejoined candidate', async () => {
await stakingContract.delegate(poolAddr.address, { value: 2 });
expect(await stakingContract.balanceOf(poolAddr.address, deployer.address)).eq(10);

await stakingContract.connect(userA).delegate(poolAddr.address, { value: 2 });
await stakingContract.connect(userB).delegate(poolAddr.address, { value: 2 });
expect(
await stakingContract.bulkBalanceOf([poolAddr.address, poolAddr.address], [userA.address, userB.address])
).eql([2, 2].map(BigNumber.from));

await stakingContract.connect(userA).undelegate(poolAddr.address, 2);
await stakingContract.connect(userB).undelegate(poolAddr.address, 1);
expect(
await stakingContract.bulkBalanceOf([poolAddr.address, poolAddr.address], [userA.address, userB.address])
).eql([0, 1].map(BigNumber.from));
});
});
});