Skip to content
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
19 changes: 19 additions & 0 deletions contracts/RewardsDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,25 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad
return rewards;
}

function claimForDelegate(address runner, address user) public returns (uint256) {
require(
!(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()),
'G019'
);
uint256 rewards = userRewards(runner, user);
if (rewards == 0) return 0;
info[runner].rewardDebt[user] += rewards;

// delegate
IERC20(settings.getContractAddress(SQContracts.SQToken)).safeTransfer(
settings.getContractAddress(SQContracts.Staking),
rewards
);

emit ClaimRewards(runner, user, rewards);
return rewards;
}

/**
* @notice extract for reuse emit RewardsChanged event
*/
Expand Down
64 changes: 59 additions & 5 deletions contracts/RewardsStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
_;
}

modifier onlyStakingManager() {
require(msg.sender == settings.getContractAddress(SQContracts.StakingManager), 'G016');
_;
}

modifier onlyIndexerRegistry() {
require(msg.sender == settings.getContractAddress(SQContracts.IndexerRegistry), 'G017');
_;
Expand Down Expand Up @@ -174,7 +179,7 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
//make sure the eraReward be 0, when runner reregister
rewardsDistributor.resetEraReward(_runner, currentEra);

_updateTotalStakingAmount(stakingManager, _runner, 0, false);
_updateTotalStakingAmount(stakingManager, _runner, 0, currentEra, false);

//apply first onICRChgange
uint256 newCommissionRate = IIndexerRegistry(
Expand Down Expand Up @@ -254,7 +259,8 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
IStakingManager stakingManager = IStakingManager(
settings.getContractAddress(SQContracts.StakingManager)
);
uint256 newDelegation = stakingManager.getAfterDelegationAmount(staker, runner);
uint256 currentEra = _getCurrentEra();
uint256 newDelegation = stakingManager.getEraDelegationAmount(staker, runner, currentEra);

// test whether it is runner's Stake Change
if (staker == runner) {
Expand All @@ -277,7 +283,7 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
pendingStakerNos[runner][lastStaker] = stakerIndex;
pendingStakeChangeLength[runner]--;

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

// notify stake allocation
Expand All @@ -287,6 +293,47 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
stakingAllocation.onStakeUpdate(runner);
}

function applyRedelegation(address runner, address staker) external onlyStakingManager {
IRewardsDistributor rewardsDistributor = _getRewardsDistributor();
IndexerRewardInfo memory rewardInfo = rewardsDistributor.getRewardInfo(runner);
uint256 currentEra = _getCurrentEra();

require(lastSettledEra[runner] == currentEra - 1, 'RS007');

// run hook for delegation change
IStakingManager stakingManager = IStakingManager(
settings.getContractAddress(SQContracts.StakingManager)
);
uint256 newDelegation = stakingManager.getEraDelegationAmount(staker, runner, currentEra);

// 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 newRewardDebt = MathUtil.mulDiv(
delegation[staker][runner],
rewardInfo.accSQTPerStake,
PER_TRILL
);
rewardsDistributor.setRewardDebt(runner, staker, newRewardDebt);

// since lastSettledEra is (currentEra - 1), lastClaimedEra must equal to lastSettledEra
_updateTotalStakingAmount(stakingManager, runner, lastSettledEra[runner], currentEra, true);
emit StakeChanged(runner, staker, delegation[staker][runner]);

// notify stake allocation
IStakingAllocation stakingAllocation = IStakingAllocation(
settings.getContractAddress(SQContracts.StakingAllocation)
);
stakingAllocation.onStakeUpdate(runner);
}

/**
* @dev Apply the CommissionRate change and update the commissionRates stored in contract states.
*/
Expand All @@ -310,7 +357,13 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
).getCommissionRate(runner);
commissionRates[runner] = newCommissionRate;
pendingCommissionRateChange[runner] = 0;
_updateTotalStakingAmount(stakingManager, runner, rewardInfo.lastClaimEra, true);
_updateTotalStakingAmount(
stakingManager,
runner,
rewardInfo.lastClaimEra,
currentEra,
true
);
emit ICRChanged(runner, newCommissionRate);
}

Expand Down Expand Up @@ -382,10 +435,11 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
IStakingManager stakingManager,
address runner,
uint256 lastClaimEra,
uint256 currentEra,
bool doCheck
) private {
if (!doCheck || checkAndReflectSettlement(runner, lastClaimEra)) {
uint256 runnerStake = stakingManager.getAfterDelegationAmount(runner, runner);
uint256 runnerStake = stakingManager.getEraDelegationAmount(runner, runner, currentEra);
totalStakingAmount[runner] =
stakingManager.getTotalStakingAmount(runner) +
MathUtil.mulDiv(runnerStake, (runnerStakeWeight() - PER_MILL), PER_MILL);
Expand Down
25 changes: 22 additions & 3 deletions contracts/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter {
*/
event DelegationAdded(address indexed source, address indexed runner, uint256 amount);

/**
* @dev Emitted when stake to an Runner, with instant indicator.
*/
event DelegationAdded2(
address indexed source,
address indexed runner,
uint256 amount,
bool instant
);

/**
* @dev Emitted when unstake to an Runner.
*/
Expand Down Expand Up @@ -296,7 +306,12 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter {
emit UnbondCancelled(_source, ua.indexer, ua.amount, _unbondReqId);
}

function addDelegation(address _source, address _runner, uint256 _amount) external {
function addDelegation(
address _source,
address _runner,
uint256 _amount,
bool instant
) external {
require(
msg.sender == settings.getContractAddress(SQContracts.StakingManager) ||
msg.sender == address(this),
Expand All @@ -322,13 +337,17 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter {
delegation[_source][_runner].valueAfter = _amount;
totalStakingAmount[_runner].valueAfter = _amount;
} else {
if (instant) {
delegation[_source][_runner].valueAt += _amount;
totalStakingAmount[_runner].valueAt += _amount;
}
delegation[_source][_runner].valueAfter += _amount;
totalStakingAmount[_runner].valueAfter += _amount;
}
lockedAmount[_source] += _amount;
_onDelegationChange(_source, _runner);

emit DelegationAdded(_source, _runner, _amount);
emit DelegationAdded2(_source, _runner, _amount, instant);
}

function delegateToIndexer(
Expand All @@ -342,7 +361,7 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter {
_amount
);

this.addDelegation(_source, _runner, _amount);
this.addDelegation(_source, _runner, _amount, false);
}

function removeDelegation(address _source, address _runner, uint256 _amount) external {
Expand Down
62 changes: 46 additions & 16 deletions contracts/StakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@

pragma solidity 0.8.15;

import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';

import './interfaces/IRewardsDistributor.sol';
import './Staking.sol';
import './interfaces/IStakingManager.sol';
import './interfaces/IIndexerRegistry.sol';

import './interfaces/IEraManager.sol';
import './utils/StakingUtil.sol';
import './interfaces/IIndexerRegistry.sol';
import './interfaces/IStakingManager.sol';
import './utils/MathUtil.sol';
import './utils/StakingUtil.sol';
import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';

/**
* Split from Staking, to keep contract size under control
Expand Down Expand Up @@ -109,7 +110,30 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable {
staking.checkDelegateLimitation(_toRunner, _amount);

staking.removeDelegation(_source, _fromRunner, _amount);
staking.addDelegation(_source, _toRunner, _amount);
staking.addDelegation(_source, _toRunner, _amount, false);
}

// @dev delegate rewards to node operator, can be used by both node operator & delegator
// can be called even when the node operator has reached the max delegation limit
// can not be called when the node operator hasn't collected latest rewards
// can not be called when the node operator is unregistered
// @param _runner the node operator address
function delegateReward(address _runner) external {
Staking staking = Staking(settings.getContractAddress(SQContracts.Staking));
address staker = msg.sender;
// runner should be valid in the following era.
require(this.getAfterDelegationAmount(_runner, _runner) > 0, 'S012');
IRewardsDistributor rewardsDistributor = IRewardsDistributor(
settings.getContractAddress(SQContracts.RewardsDistributor)
);
// rewards sent to Staking from rewardsDistributor
uint256 rewards = rewardsDistributor.claimForDelegate(_runner, staker);
require(rewards > 0, 'S011');
staking.addDelegation(staker, _runner, rewards, true);
IRewardsStaking rewardsStaking = IRewardsStaking(
settings.getContractAddress(SQContracts.RewardsStaking)
);
rewardsStaking.applyRedelegation(_runner, staker);
}

function cancelUnbonding(uint256 unbondReqId) external {
Expand All @@ -127,10 +151,8 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable {
require(indexerRegistry.isIndexer(indexer), 'S007');

staking.removeUnbondingAmount(msg.sender, unbondReqId);
// if (msg.sender != indexer) {
// staking.checkDelegateLimitation(indexer, amount);
// }
staking.addDelegation(msg.sender, indexer, amount);

staking.addDelegation(msg.sender, indexer, amount, false);
}

/**
Expand Down Expand Up @@ -189,13 +211,21 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable {
return StakingUtil.currentStaking(sm, _currentEra);
}

function getDelegationAmount(address _source, address _runner) public view returns (uint256) {
function getDelegationAmount(
address _source,
address _runner
) external view override returns (uint256) {
uint256 eraNumber = IEraManager(settings.getContractAddress(SQContracts.EraManager))
.eraNumber();
Staking staking = Staking(settings.getContractAddress(SQContracts.Staking));
(uint256 era, uint256 valueAt, uint256 valueAfter) = staking.delegation(_source, _runner);
StakingAmount memory sm = StakingAmount(era, valueAt, valueAfter);
return StakingUtil.currentStaking(sm, eraNumber);
return _getCurrentDelegationAmount(_source, _runner, eraNumber);
}

function getEraDelegationAmount(
address _source,
address _runner,
uint256 _era
) external view override returns (uint256) {
return _getCurrentDelegationAmount(_source, _runner, _era);
}

function getTotalStakingAmount(address _runner) public view override returns (uint256) {
Expand Down
2 changes: 2 additions & 0 deletions contracts/interfaces/IRewardsDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ interface IRewardsDistributor {
function userRewards(address indexer, address user) external view returns (uint256);

function getRewardInfo(address indexer) external view returns (IndexerRewardInfo memory);

function claimForDelegate(address runner, address user) external returns (uint256);
}
2 changes: 2 additions & 0 deletions contracts/interfaces/IRewardsStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ interface IRewardsStaking {
function getDelegationAmount(address source, address indexer) external view returns (uint256);

function applyRunnerWeightChange(address _runner) external;

function applyRedelegation(address runner, address staker) external;
}
11 changes: 11 additions & 0 deletions contracts/interfaces/IStakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,15 @@ interface IStakingManager {
address _delegator,
address _runner
) external view returns (uint256);

function getDelegationAmount(
address _delegator,
address _runner
) external view returns (uint256);

function getEraDelegationAmount(
address _delegator,
address _runner,
uint256 _era
) external view returns (uint256);
}
24 changes: 24 additions & 0 deletions publish/ABI/RewardsDistributor.json
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,30 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "runner",
"type": "address"
},
{
"internalType": "address",
"name": "user",
"type": "address"
}
],
"name": "claimForDelegate",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
18 changes: 18 additions & 0 deletions publish/ABI/RewardsStaking.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,24 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "runner",
"type": "address"
},
{
"internalType": "address",
"name": "staker",
"type": "address"
}
],
"name": "applyRedelegation",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
Loading