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

[Staking] Update reward calculation mechanism #44

Merged
merged 7 commits into from
Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
84 changes: 33 additions & 51 deletions contracts/interfaces/IRewardPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,66 @@

pragma solidity ^0.8.9;

interface IRewardPool {
/// @dev Emitted when the settled pool is updated.
event SettledPoolsUpdated(address[] poolAddress, uint256[] accumulatedRps);
/// @dev Emitted when the pending pool is updated.
event PendingPoolUpdated(address poolAddress, uint256 accumulatedRps);
/// @dev Emitted when the fields to calculate settled reward for the user is updated.
event SettledRewardUpdated(address poolAddress, address user, uint256 debited, uint256 accumulatedRps);
import "../interfaces/consumers/PeriodWrapperConsumer.sol";

interface IRewardPool is PeriodWrapperConsumer {
/// @dev Emitted when the fields to calculate pending reward for the user is updated.
event PendingRewardUpdated(address poolAddress, address user, uint256 debited, uint256 credited);
event UserRewardUpdated(address indexed poolAddr, address indexed user, uint256 debited);
/// @dev Emitted when the user claimed their reward
event RewardClaimed(address poolAddress, address user, uint256 amount);
event RewardClaimed(address indexed poolAddr, address indexed user, uint256 amount);

struct PendingRewardFields {
// Recorded reward amount.
uint256 debited;
// The amount rewards that user have already earned.
uint256 credited;
// Last period number that the info updated.
uint256 lastSyncedPeriod;
}
/// @dev Emitted when the pool shares are updated
event PoolSharesUpdated(uint256 indexed period, address indexed poolAddr, uint256 shares);
/// @dev Emitted when the pools are updated
event PoolsUpdated(uint256 indexed period, address[] poolAddrs, uint256[] aRps, uint256[] shares);
/// @dev Emitted when the contract fails when updating the pools
event PoolsUpdateFailed(uint256 indexed period, address[] poolAddrs, uint256[] rewards);
/// @dev Emitted when the contract fails when updating a pool that already set
event PoolUpdateConflicted(uint256 indexed period, address indexed poolAddr);

struct SettledRewardFields {
struct UserRewardFields {
// Recorded reward amount.
uint256 debited;
// Accumulated of the amount rewards per share (one unit staking).
uint256 accumulatedRps;
}

struct PendingPool {
// Accumulated of the amount rewards per share (one unit staking).
uint256 accumulatedRps;
// The last accumulated of the amount rewards per share (one unit staking) that the info updated.
uint256 aRps;
// Min staking amount in the period.
uint256 minAmount;
// Last period number that the info updated.
uint256 lastPeriod;
}

struct SettledPool {
// Last period number that the info updated.
uint256 lastSyncedPeriod;
struct PoolFields {
// Accumulated of the amount rewards per share (one unit staking).
uint256 accumulatedRps;
uint256 aRps;
// The staking total to share reward of the current period.
PeriodWrapper shares;
}

/**
* @dev Returns total rewards from scratch including pending reward and claimable reward except the claimed amount.
*
* Note: Do not use this function to get claimable reward, consider using the method `getClaimableReward` instead.
*
*/
function getTotalReward(address _poolAddr, address _user) external view returns (uint256);

/**
* @dev Returns the reward amount that user claimable.
*/
function getClaimableReward(address _poolAddr, address _user) external view returns (uint256);

/**
* @dev Returns the pending reward.
*/
function getPendingReward(address _poolAddr, address _user) external view returns (uint256 _amount);
function getReward(address _poolAddr, address _user) external view returns (uint256);

/**
* @dev Returns the staked amount of the user.
* @dev Returns the staking amount of an user.
*/
function balanceOf(address _poolAddr, address _user) external view returns (uint256);
function stakingAmountOf(address _poolAddr, address _user) external view returns (uint256);

/**
* @dev Returns the staked amounts of the users.
* @dev Returns the staking amounts of the users.
*/
function bulkBalanceOf(address[] calldata _poolAddrs, address[] calldata _userList)
function bulkStakingAmountOf(address[] calldata _poolAddrs, address[] calldata _userList)
external
view
returns (uint256[] memory);

/**
* @dev Returns the total staked amount of all users.
* @dev Returns the total staking amount of all users for a pool.
*/
function totalBalance(address _poolAddr) external view returns (uint256);
function stakingTotal(address _poolAddr) external view returns (uint256);

/**
* @dev Returns the total staked amount of all users.
* @dev Returns the total staking amounts of all users for the pools `_poolAddrs`.
*/
function totalBalances(address[] calldata _poolAddr) external view returns (uint256[] memory);
function bulkStakingTotal(address[] calldata _poolAddrs) external view returns (uint256[] memory);
}
80 changes: 32 additions & 48 deletions contracts/interfaces/IStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ interface IStaking is IRewardPool {
address addr;
// Pool admin address
address admin;
// Self-staked amount
uint256 stakedAmount;
// Total balance of the pool
uint256 totalBalance;
// Mapping from delegator => delegated amount
mapping(address => uint256) delegatedAmount;
// Self-staking amount
uint256 stakingAmount;
// Total number of RON staking for the pool
uint256 stakingTotal;
// Mapping from delegator => delegating amount
mapping(address => uint256) delegatingAmount;
}

/// @dev Emitted when the validator pool is approved.
event PoolApproved(address indexed validator, address indexed admin);
/// @dev Emitted when the validator pool is deprecated.
event PoolsDeprecated(address[] validator);
/// @dev Emitted when the staked amount is deprecated.
event StakedAmountDeprecated(address indexed validator, address indexed admin, uint256 amount);
/// @dev Emitted when the staking amount is deprecated.
event StakingAmountDeprecated(address indexed validator, address indexed admin, uint256 amount);
/// @dev Emitted when the pool admin staked for themself.
event Staked(address indexed consensuAddr, uint256 amount);
/// @dev Emitted when the pool admin unstaked the amount of RON from themself.
Expand All @@ -32,8 +32,8 @@ interface IStaking is IRewardPool {
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);
/// @dev Emitted when the minimum staking amount for being a validator is updated.
event MinValidatorStakingAmountUpdated(uint256 threshold);

///////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS FOR GOVERNANCE //
Expand All @@ -42,68 +42,52 @@ interface IStaking is IRewardPool {
/**
* @dev Returns the minimum threshold for being a validator candidate.
*/
function minValidatorBalance() external view returns (uint256);
function minValidatorStakingAmount() external view returns (uint256);

/**
* @dev Sets the minimum threshold for being a validator candidate.
*
* Requirements:
* - The method caller is admin.
*
* Emits the `MinValidatorBalanceUpdated` event.
* Emits the `MinValidatorStakingAmountUpdated` event.
*
*/
function setMinValidatorBalance(uint256) external;
function setMinValidatorStakingAmount(uint256) external;

///////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS FOR VALIDATOR CONTRACT //
///////////////////////////////////////////////////////////////////////////////////////

/**
* @dev Records the amount of reward `_reward` for the pending pool `_poolAddr`.
* @dev Records the amount of rewards `_rewards` for the pools `_poolAddrs`.
*
* Requirements:
* - The method caller is validator contract.
*
* Emits the `PendingPoolUpdated` event.
* Emits the event `PoolsUpdated` once the contract recorded the rewards successfully.
* Emits the event `PoolsUpdateFailed` once the input array lengths are not equal.
* Emits the event `PoolUpdateConflicted` when the pool is already updated in the period.
*
* Note: This method should not be called after the pending pool is sinked.
* Note: This method should be called once at the period ending.
*
*/
function recordReward(address _consensusAddr, uint256 _reward) external payable;

/**
* @dev Settles the pending pool and allocates rewards for the pool `_consensusAddr`.
*
* Requirements:
* - The method caller is validator contract.
*
* Emits the `SettledPoolsUpdated` event.
*
*/
function settleRewardPools(address[] calldata _consensusAddrs) external;

/**
* @dev Handles when the pending reward pool of the validator is sinked.
*
* Requirements:
* - The method caller is validator contract.
*
* Emits the `PendingPoolUpdated` event.
*
*/
function sinkPendingReward(address _consensusAddr) external;
function recordRewards(
uint256 _period,
address[] calldata _consensusAddrs,
uint256[] calldata _rewards
) external payable;

/**
* @dev Deducts from staked amount of the validator `_consensusAddr` for `_amount`.
* @dev Deducts from staking amount of the validator `_consensusAddr` for `_amount`.
*
* Requirements:
* - The method caller is validator contract.
*
* Emits the event `Unstaked`.
*
*/
function deductStakedAmount(address _consensusAddr, uint256 _amount) external;
function deductStakingAmount(address _consensusAddr, uint256 _amount) external;

/**
* @dev Deprecates the pool.
Expand All @@ -112,7 +96,7 @@ interface IStaking is IRewardPool {
* - The method caller is validator contract.
*
* Emits the event `PoolsDeprecated` and `Unstaked` events.
* Emits the event `StakedAmountDeprecated` if the contract cannot transfer RON back to the pool admin.
* Emits the event `StakingAmountDeprecated` if the contract cannot transfer RON back to the pool admin.
*
*/
function deprecatePools(address[] calldata _pools) external;
Expand All @@ -127,7 +111,7 @@ interface IStaking is IRewardPool {
* Requirements:
* - The method caller is able to receive RON.
* - The treasury is able to receive RON.
* - The amount is larger than or equal to the minimum validator balance `minValidatorBalance()`.
* - The amount is larger than or equal to the minimum validator staking amount `minValidatorStakingAmount()`.
*
* Emits the event `PoolApproved`.
*
Expand Down Expand Up @@ -169,7 +153,7 @@ interface IStaking is IRewardPool {
function unstake(address _consensusAddr, uint256 _amount) external;

/**
* @dev Renounces being a validator candidate and takes back the delegated/staked amount.
* @dev Renounces being a validator candidate and takes back the delegating/staking amount.
*
* Requirements:
* - The consensus address is a validator candidate.
Expand Down Expand Up @@ -233,12 +217,12 @@ interface IStaking is IRewardPool {
) external;

/**
* @dev Returns the pending reward and the claimable reward of the user `_user`.
* @dev Returns the claimable reward of the user `_user`.
*/
function getRewards(address _user, address[] calldata _poolAddrList)
external
view
returns (uint256[] memory _pendings, uint256[] memory _claimables);
returns (uint256[] memory _rewards);

/**
* @dev Claims the reward of method caller.
Expand Down Expand Up @@ -270,7 +254,7 @@ interface IStaking is IRewardPool {
view
returns (
address _admin,
uint256 _stakedAmount,
uint256 _totalBalance
uint256 _stakingAmount,
uint256 _stakingTotal
);
}
11 changes: 11 additions & 0 deletions contracts/interfaces/consumers/PeriodWrapperConsumer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface PeriodWrapperConsumer {
struct PeriodWrapper {
// Inner value.
uint256 inner;
// Last period number that the info updated.
uint256 lastPeriod;
}
}
4 changes: 2 additions & 2 deletions contracts/mocks/MockPrecompile.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ contract MockPrecompile {

function pickValidatorSet(
address[] memory _candidates,
uint256[] memory _balanceWeights,
uint256[] memory _weights,
uint256[] memory _trustedWeights,
uint256 _maxValidatorNumber,
uint256 _maxPrioritizedValidatorNumber
) public pure returns (address[] memory _result) {
(_result, _trustedWeights) = Sorting.sortWithExternalKeys(_candidates, _balanceWeights, _trustedWeights);
(_result, _trustedWeights) = Sorting.sortWithExternalKeys(_candidates, _weights, _trustedWeights);
uint256 _newValidatorCount = Math.min(_maxValidatorNumber, _result.length);
_arrangeValidatorCandidates(_result, _trustedWeights, _newValidatorCount, _maxPrioritizedValidatorNumber);
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/mocks/MockRoninValidatorSetOverridePrecompile.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ contract MockRoninValidatorSetOverridePrecompile is RoninValidatorSet, MockPreco

function _pcPickValidatorSet(
address[] memory _candidates,
uint256[] memory _balanceWeights,
uint256[] memory _weights,
uint256[] memory _trustedWeights,
uint256 _maxValidatorNumber,
uint256 _maxPrioritizedValidatorNumber
) internal pure override returns (address[] memory _result, uint256 _newValidatorCount) {
_result = pickValidatorSet(
_candidates,
_balanceWeights,
_weights,
_trustedWeights,
_maxValidatorNumber,
_maxPrioritizedValidatorNumber
Expand Down
Loading