Skip to content

Commit

Permalink
make node operator stake weighted (#398)
Browse files Browse the repository at this point in the history
* make node operator stake weighted

* change total staking amount

* bugfix

* fix

* remove .only

* fixes and more tests

* upgrade testnet

* introduce new events

* remove .only

* upgrade to testnet

* [SKIP CI] Prerelease

* use constant
  • Loading branch information
ianhe8x authored May 20, 2024
1 parent 6d13367 commit 2c008e7
Show file tree
Hide file tree
Showing 8 changed files with 514 additions and 70 deletions.
2 changes: 1 addition & 1 deletion contracts/RewardsDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad
);
rewardsStaking.checkAndReflectSettlement(runner, rewardInfo.lastClaimEra);
require(rewardInfo.lastClaimEra <= rewardsStaking.getLastSettledEra(runner), 'RD005');

rewardsStaking.applyRunnerWeightChange(runner);
rewardInfo.lastClaimEra++;

// claim rewards pool.
Expand Down
113 changes: 105 additions & 8 deletions contracts/RewardsStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
//Era number of CommissionRateChange should apply: runner => CommissionRateChange Era number
mapping(address => uint256) private pendingCommissionRateChange;

//Last settled Era number: runner => lastSettledEra
//Last settled Era number: runner => lastSettledEra this is the last era runner have applied all stake changes
mapping(address => uint256) private lastSettledEra;

//total staking amount per runner: runner => totalStakingAmount
Expand All @@ -71,6 +71,11 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
//rewards commission rates per runner: runner => commissionRates
mapping(address => uint256) private commissionRates;

// @notice Node Runner Stake Weight (PerMill), must be > 1e6
uint256 private _runnerStakeWeight;

mapping(address => uint256) private _previousRunnerStakeWeights;

// -- Events --

/**
Expand All @@ -88,6 +93,14 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
*/
event SettledEraUpdated(address indexed runner, uint256 era);

// @dev used for _runnerStakeWeight and other global param changes
event ParameterUpdated(string param, uint256 value);

/**
* @dev Emitted when _previousRunnerStakeWeights is update.
*/
event RunnerWeightApplied(address indexed runner, uint256 weight);

/**
* @dev Initialize this contract.
*/
Expand All @@ -112,6 +125,11 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
_;
}

function setRunnerStakeWeight(uint256 _weight) external onlyOwner {
_runnerStakeWeight = _weight;
emit ParameterUpdated('RunnerStakeWeight', _weight);
}

/**
* @dev Callback method of stake change, called by Staking contract when
* Indexers or Delegators try to change their stake amount.
Expand All @@ -137,6 +155,13 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
);
//apply first onStakeChange
uint256 newDelegation = stakingManager.getAfterDelegationAmount(_runner, _runner);
// apply _runnerStakeWeight
uint256 _runnerStakeWeight = runnerStakeWeight();
newDelegation = MathUtil.mulDiv(newDelegation, _runnerStakeWeight, PER_MILL);
if (_previousRunnerStakeWeights[_runner] != _runnerStakeWeight) {
_setPreviousRunnerStakeWeights(_runner, _runnerStakeWeight);
}
// end
delegation[_runner][_runner] = newDelegation;

uint256 newAmount = MathUtil.mulDiv(
Expand All @@ -149,7 +174,7 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
//make sure the eraReward be 0, when runner reregister
rewardsDistributor.resetEraReward(_runner, currentEra);

totalStakingAmount[_runner] = stakingManager.getTotalStakingAmount(_runner);
_updateTotalStakingAmount(stakingManager, _runner, 0, false);

//apply first onICRChgange
uint256 newCommissionRate = IIndexerRegistry(
Expand All @@ -173,7 +198,11 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
IIndexerRegistry(settings.getContractAddress(SQContracts.IndexerRegistry))
.isIndexer(_runner)
) {
require(rewardsDistributor.collectAndDistributeEraRewards(currentEra, _runner) == lastEra, 'RS002');
require(
rewardsDistributor.collectAndDistributeEraRewards(currentEra, _runner) ==
lastEra,
'RS002'
);
IndexerRewardInfo memory rewardInfo = rewardsDistributor.getRewardInfo(_runner);
require(checkAndReflectSettlement(_runner, rewardInfo.lastClaimEra), 'RS003');
}
Expand Down Expand Up @@ -226,6 +255,15 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
settings.getContractAddress(SQContracts.StakingManager)
);
uint256 newDelegation = stakingManager.getAfterDelegationAmount(staker, runner);

// test whether it is runner's Stake Change
if (staker == runner) {
uint256 _runnerStakeWeight = runnerStakeWeight();
newDelegation = MathUtil.mulDiv(newDelegation, _runnerStakeWeight, PER_MILL);
if (_previousRunnerStakeWeights[runner] != _runnerStakeWeight) {
_setPreviousRunnerStakeWeights(runner, _runnerStakeWeight);
}
}
delegation[staker][runner] = newDelegation;

uint256 newAmount = MathUtil.mulDiv(newDelegation, rewardInfo.accSQTPerStake, PER_TRILL);
Expand All @@ -239,7 +277,7 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
pendingStakerNos[runner][lastStaker] = stakerIndex;
pendingStakeChangeLength[runner]--;

_updateTotalStakingAmount(stakingManager, runner, lastClaimEra);
_updateTotalStakingAmount(stakingManager, runner, lastClaimEra, true);
emit StakeChanged(runner, staker, newDelegation);

// notify stake allocation
Expand Down Expand Up @@ -272,7 +310,7 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
).getCommissionRate(runner);
commissionRates[runner] = newCommissionRate;
pendingCommissionRateChange[runner] = 0;
_updateTotalStakingAmount(stakingManager, runner, rewardInfo.lastClaimEra);
_updateTotalStakingAmount(stakingManager, runner, rewardInfo.lastClaimEra, true);
emit ICRChanged(runner, newCommissionRate);
}

Expand Down Expand Up @@ -301,6 +339,39 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
return false;
}

/**
* @dev Called by RewardsDistributor#collectAndDistributeEraRewards(), apply
* Require to be true when someone try to claimRewards() or onStakeChangeRequested().
*/
function applyRunnerWeightChange(address _runner) public {
uint256 _runnerStakeWeight = runnerStakeWeight();
uint256 _previousRunnerStakeWeight = previousRunnerStakeWeight(_runner);
if (_runnerStakeWeight != _previousRunnerStakeWeight) {
IRewardsDistributor rewardsDistributor = _getRewardsDistributor();
rewardsDistributor.claimFrom(_runner, _runner);
IndexerRewardInfo memory rewardInfo = rewardsDistributor.getRewardInfo(_runner);
// increase runner stake
uint256 currentStake = delegation[_runner][_runner];
// can not find unaltered ownstake, revert calculate from currentStake
uint256 newStake = MathUtil.mulDiv(
currentStake,
_runnerStakeWeight,
_previousRunnerStakeWeight
);
// assert(newStake >= currentStake, 'error todo');
uint256 newDebtAmount = MathUtil.mulDiv(newStake, rewardInfo.accSQTPerStake, PER_TRILL);
rewardsDistributor.setRewardDebt(_runner, _runner, newDebtAmount);
delegation[_runner][_runner] = newStake;
if (newStake > currentStake) {
totalStakingAmount[_runner] += newStake - currentStake;
} else {
totalStakingAmount[_runner] -= currentStake - newStake;
}
_setPreviousRunnerStakeWeights(_runner, _runnerStakeWeight);
}
// else skip
}

/**
* @dev Update the totalStakingAmount of the runner with the state from Staking contract.
* Called when applyStakeChange or applyICRChange.
Expand All @@ -310,10 +381,14 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
function _updateTotalStakingAmount(
IStakingManager stakingManager,
address runner,
uint256 lastClaimEra
uint256 lastClaimEra,
bool doCheck
) private {
if (checkAndReflectSettlement(runner, lastClaimEra)) {
totalStakingAmount[runner] = stakingManager.getTotalStakingAmount(runner);
if (!doCheck || checkAndReflectSettlement(runner, lastClaimEra)) {
uint256 runnerStake = stakingManager.getAfterDelegationAmount(runner, runner);
totalStakingAmount[runner] =
stakingManager.getTotalStakingAmount(runner) +
MathUtil.mulDiv(runnerStake, (runnerStakeWeight() - PER_MILL), PER_MILL);
}
}

Expand All @@ -339,6 +414,11 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
return pendingStakers[_runner][pendingStakerNos[_runner][_staker]] == _staker;
}

function _setPreviousRunnerStakeWeights(address _runner, uint256 _weight) private {
_previousRunnerStakeWeights[_runner] = _weight;
emit RunnerWeightApplied(_runner, _weight);
}

// -- Views --
function getTotalStakingAmount(address runner) public view returns (uint256) {
return totalStakingAmount[runner];
Expand Down Expand Up @@ -367,4 +447,21 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
function getPendingStaker(address runner, uint256 i) public view returns (address) {
return pendingStakers[runner][i];
}

function runnerStakeWeight() public view returns (uint256) {
if (_runnerStakeWeight < PER_MILL) {
return PER_MILL;
} else {
return _runnerStakeWeight;
}
}

function previousRunnerStakeWeight(address runner) public view returns (uint256) {
uint256 runnerStakeWeight = _previousRunnerStakeWeights[runner];
if (runnerStakeWeight < PER_MILL) {
return PER_MILL;
} else {
return runnerStakeWeight;
}
}
}
2 changes: 2 additions & 0 deletions contracts/interfaces/IRewardsStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ interface IRewardsStaking {
function getLastSettledEra(address indexer) external view returns (uint256);

function getDelegationAmount(address source, address indexer) external view returns (uint256);

function applyRunnerWeightChange(address _runner) external;
}
96 changes: 96 additions & 0 deletions publish/ABI/RewardsStaking.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,44 @@
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "string",
"name": "param",
"type": "string"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "ParameterUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "runner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "weight",
"type": "uint256"
}
],
"name": "RunnerWeightApplied",
"type": "event"
},
{
"anonymous": false,
"inputs": [
Expand Down Expand Up @@ -107,6 +145,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_runner",
"type": "address"
}
],
"name": "applyRunnerWeightChange",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -354,13 +405,58 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "runner",
"type": "address"
}
],
"name": "previousRunnerStakeWeight",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "runnerStakeWeight",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_weight",
"type": "uint256"
}
],
"name": "setRunnerStakeWeight",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
6 changes: 3 additions & 3 deletions publish/testnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@
"lastUpdate": "Fri, 09 Feb 2024 05:52:10 GMT"
},
"RewardsStaking": {
"innerAddress": "0x76105B682f20977FD4B178271739B0737F6dC33c",
"innerAddress": "0x04Cd739fE7E1a684f3c97F1EE09894c66F51a104",
"address": "0xB64D73B96358855075576D66746D2a88e043CC1E",
"bytecodeHash": "ba0b25deebb4f77bf140d5d3d6987a3df7b943c4f30afd9ad2654845dc1e119b",
"lastUpdate": "Thu, 28 Mar 2024 07:11:47 GMT"
"bytecodeHash": "973d6f56de547f460b966b06a0189163146471417c3d8d25e47217315fd78b26",
"lastUpdate": "Mon, 06 May 2024 21:47:28 GMT"
},
"RewardsHelper": {
"innerAddress": "0xa7eE3bFD854bd609D1485FE845d996EEDE87aF7B",
Expand Down
Loading

0 comments on commit 2c008e7

Please sign in to comment.