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
26 changes: 21 additions & 5 deletions contracts/StakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -118,22 +118,38 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable {
// 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 {
function stakeReward(address _runner) external {
_stakeReward(msg.sender, _runner, false);
}

// @dev batch version of stakeReward
function batchStakeReward(address[] calldata _runners) external {
for (uint256 i = 0; i < _runners.length; i++) {
_stakeReward(msg.sender, _runners[i], true);
}
}

function _stakeReward(address _staker, address _runner, bool _skipError) internal {
Staking staking = Staking(settings.getContractAddress(SQContracts.Staking));
address staker = msg.sender;
// runner should be valid in the following era.
if (_skipError && this.getAfterDelegationAmount(_runner, _runner) == 0) {
return;
}
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);
uint256 rewards = rewardsDistributor.claimForDelegate(_runner, _staker);
if (_skipError && rewards == 0) {
return;
}
require(rewards > 0, 'S011');
staking.addDelegation(staker, _runner, rewards, true);
staking.addDelegation(_staker, _runner, rewards, true);
IRewardsStaking rewardsStaking = IRewardsStaking(
settings.getContractAddress(SQContracts.RewardsStaking)
);
rewardsStaking.applyRedelegation(_runner, staker);
rewardsStaking.applyRedelegation(_runner, _staker);
}

function cancelUnbonding(uint256 unbondReqId) external {
Expand Down
37 changes: 25 additions & 12 deletions publish/ABI/StakingManager.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,25 @@
{
"inputs": [
{
"internalType": "uint256",
"name": "unbondReqId",
"type": "uint256"
"internalType": "address[]",
"name": "_runners",
"type": "address[]"
}
],
"name": "cancelUnbonding",
"name": "batchStakeReward",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_runner",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"name": "unbondReqId",
"type": "uint256"
}
],
"name": "delegate",
"name": "cancelUnbonding",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
Expand All @@ -68,9 +63,14 @@
"internalType": "address",
"name": "_runner",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "delegateReward",
"name": "delegate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
Expand Down Expand Up @@ -363,6 +363,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_runner",
"type": "address"
}
],
"name": "stakeReward",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
120 changes: 85 additions & 35 deletions test/RewardsDistributer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { acceptPlan, addInstantRewards, etherParse, eventFrom, startNewEra, time
import { deployContracts } from './setup';

describe('RewardsDistributor Contract', () => {
let root, runner, consumer, delegator, delegator2;
let root, runner, runner2, runner3, consumer, delegator, delegator2;

let token: ERC20;
let staking: Staking;
Expand Down Expand Up @@ -72,7 +72,7 @@ describe('RewardsDistributor Contract', () => {

const deployer = () => deployContracts(root, runner);
before(async () => {
[root, runner, consumer, delegator, delegator2] = await ethers.getSigners();
[root, runner, runner2, runner3, consumer, delegator, delegator2] = await ethers.getSigners();
});

beforeEach(async () => {
Expand Down Expand Up @@ -102,10 +102,13 @@ describe('RewardsDistributor Contract', () => {
//register an new Indexer with Initial Commission Rate: 10% and Initial Staking Amount: 1000
//moved to era 2
await registerIndexer(root, runner, runnerInitialStake, runnerCr);
await registerIndexer(root, runner2, runnerInitialStake, runnerCr);
await registerIndexer(root, runner3, runnerInitialStake, runnerCr);
await registerIndexer(root, root, runnerInitialStake, runnerCr);
await projectRegistry.createProject(METADATA_HASH, VERSION, DEPLOYMENT_ID, 0);
// wallet_0 start project
await projectRegistry.connect(runner).startService(DEPLOYMENT_ID);
await projectRegistry.connect(runner2).startService(DEPLOYMENT_ID);
await projectRegistry.connect(root).startService(DEPLOYMENT_ID);
});

Expand Down Expand Up @@ -1009,11 +1012,15 @@ describe('RewardsDistributor Contract', () => {
await rewardsStaking.setRunnerStakeWeight(2e6);
//a 30 days agreement with 400 rewards come in at Era2
await acceptPlan(runner, consumer, 30, etherParse('3'), DEPLOYMENT_ID, token, planManager);
await acceptPlan(runner2, consumer, 30, etherParse('3'), DEPLOYMENT_ID, token, planManager);
await acceptPlan(root, consumer, 30, etherParse('3'), DEPLOYMENT_ID, token, planManager);
await staking.setIndexerLeverageLimit(20);
await token.transfer(delegator.address, delegation1);
await token.connect(delegator).increaseAllowance(staking.address, delegation1);
await stakingManager.connect(delegator).delegate(runner.address, delegation1);
await token.transfer(delegator.address, delegation2);
await token.connect(delegator).increaseAllowance(staking.address, delegation2);
await stakingManager.connect(delegator).delegate(runner2.address, delegation2);
await token.transfer(delegator2.address, delegation2);
await token.connect(delegator2).increaseAllowance(staking.address, delegation2);
await stakingManager.connect(delegator2).delegate(runner.address, delegation2);
Expand All @@ -1031,7 +1038,7 @@ describe('RewardsDistributor Contract', () => {
//delegator claim and delegate
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
expect(delegatorReward1).to.be.gt(0);
await expect(stakingManager.connect(delegator).delegateReward(runner.address))
await expect(stakingManager.connect(delegator).stakeReward(runner.address))
.to.emit(rewardsDistributor, 'ClaimRewards')
.withArgs(runner.address, delegator.address, delegatorReward1)
.to.emit(token, 'Transfer')
Expand Down Expand Up @@ -1061,7 +1068,7 @@ describe('RewardsDistributor Contract', () => {
//delegator claim and delegate
const rewards1 = await rewardsDistributor.userRewards(runner.address, runner.address);
expect(rewards1).to.be.gt(0);
await expect(stakingManager.connect(runner).delegateReward(runner.address))
await expect(stakingManager.connect(runner).stakeReward(runner.address))
.to.emit(rewardsDistributor, 'ClaimRewards')
.withArgs(runner.address, runner.address, rewards1)
.to.emit(token, 'Transfer')
Expand Down Expand Up @@ -1101,7 +1108,7 @@ describe('RewardsDistributor Contract', () => {
//delegator claim and delegate
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
expect(delegatorReward1).to.be.gt(0);
await expect(stakingManager.connect(delegator).delegateReward(runner.address))
await expect(stakingManager.connect(delegator).stakeReward(runner.address))
.to.emit(rewardsDistributor, 'ClaimRewards')
.withArgs(runner.address, delegator.address, delegatorReward1)
.to.emit(token, 'Transfer')
Expand Down Expand Up @@ -1137,7 +1144,7 @@ describe('RewardsDistributor Contract', () => {
//delegator claim and delegate
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
expect(delegatorReward1).to.be.gt(0);
await expect(stakingManager.connect(delegator).delegateReward(runner.address))
await expect(stakingManager.connect(delegator).stakeReward(runner.address))
.to.emit(rewardsDistributor, 'ClaimRewards')
.withArgs(runner.address, delegator.address, delegatorReward1)
.to.emit(token, 'Transfer')
Expand Down Expand Up @@ -1170,7 +1177,7 @@ describe('RewardsDistributor Contract', () => {
await rewardsDistributor.connect(delegator).claim(runner.address);
expect(await rewardsDistributor.userRewards(runner.address, delegator.address)).to.be.eq(0);

await expect(stakingManager.connect(delegator).delegateReward(runner.address)).to.revertedWith('S011');
await expect(stakingManager.connect(delegator).stakeReward(runner.address)).to.revertedWith('S011');
});

// when capacity full
Expand All @@ -1191,32 +1198,32 @@ describe('RewardsDistributor Contract', () => {

await expect(stakingManager.connect(delegator2).delegate(runner.address, 1)).to.be.revertedWith('S002');

//move to next era
await startNewEra(eraManager);
await rewardsHelper.connect(runner).indexerCatchup(runner.address);

//delegator claim and delegate
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
expect(delegatorReward1).to.be.gt(0);
await expect(stakingManager.connect(delegator).delegateReward(runner.address))
.to.emit(rewardsDistributor, 'ClaimRewards')
.withArgs(runner.address, delegator.address, delegatorReward1)
.to.emit(token, 'Transfer')
.withArgs(rewardsDistributor.address, staking.address, delegatorReward1);

// check userRewards
expect(await rewardsDistributor.userRewards(runner.address, delegator.address)).to.be.eq(0);
// check delegation in staking
const delegation = await staking.delegation(delegator.address, runner.address);
expect(delegation.era).to.be.eq(4);
expect(delegation.valueAt).to.be.eq(delegation1.add(delegatorReward1));
expect(delegation.valueAfter).to.be.eq(delegation1.add(delegatorReward1));
// check delegation in rewardsStaking
expect(await rewardsStaking.getDelegationAmount(delegator.address, runner.address)).to.be.eq(
delegation1.add(delegatorReward1)
);
const effectiveTotalStake = await stakingManager.getEffectiveTotalStake(runner.address);
expect(effectiveTotalStake).to.eq(runnerStake.valueAt.mul(leverageLimit));
// //move to next era
// await startNewEra(eraManager);
// await rewardsHelper.connect(runner).indexerCatchup(runner.address);
//
// //delegator claim and delegate
// const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
// expect(delegatorReward1).to.be.gt(0);
// await expect(stakingManager.connect(delegator).stakeReward(runner.address))
// .to.emit(rewardsDistributor, 'ClaimRewards')
// .withArgs(runner.address, delegator.address, delegatorReward1)
// .to.emit(token, 'Transfer')
// .withArgs(rewardsDistributor.address, staking.address, delegatorReward1);
//
// // check userRewards
// expect(await rewardsDistributor.userRewards(runner.address, delegator.address)).to.be.eq(0);
// // check delegation in staking
// const delegation = await staking.delegation(delegator.address, runner.address);
// expect(delegation.era).to.be.eq(4);
// expect(delegation.valueAt).to.be.eq(delegation1.add(delegatorReward1));
// expect(delegation.valueAfter).to.be.eq(delegation1.add(delegatorReward1));
// // check delegation in rewardsStaking
// expect(await rewardsStaking.getDelegationAmount(delegator.address, runner.address)).to.be.eq(
// delegation1.add(delegatorReward1)
// );
// const effectiveTotalStake = await stakingManager.getEffectiveTotalStake(runner.address);
// expect(effectiveTotalStake).to.eq(runnerStake.valueAt.mul(leverageLimit));
});

// when node operator not catch up
Expand All @@ -1241,7 +1248,7 @@ describe('RewardsDistributor Contract', () => {
//delegator claim and delegate
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
expect(delegatorReward1).to.be.gt(0);
await expect(stakingManager.connect(delegator).delegateReward(runner.address)).to.revertedWith('RS003');
await expect(stakingManager.connect(delegator).stakeReward(runner.address)).to.revertedWith('RS003');
});

// when node operator unregister not catch up
Expand Down Expand Up @@ -1273,7 +1280,50 @@ describe('RewardsDistributor Contract', () => {
await expect(stakingManager.connect(delegator).delegate(runner.address, 1)).to.be.revertedWith('S002');

// delegator claim and delegate
await expect(stakingManager.connect(delegator).delegateReward(runner.address)).to.be.revertedWith('S012');
await expect(stakingManager.connect(delegator).stakeReward(runner.address)).to.be.revertedWith('S012');
});

// earn rewards from runner, runner2
// no rewards from runner3
it('should allow delegator to batch claim collect and delegate', async () => {
expect(await eraManager.eraNumber()).to.be.eq(3);
expect((await rewardsDistributor.getRewardInfo(runner.address)).lastClaimEra).to.be.eq(2);
//move to next era
await startNewEra(eraManager);
await rewardsHelper.connect(runner).indexerCatchup(runner.address);
await rewardsHelper.connect(runner2).indexerCatchup(runner2.address);

// single stakeReward checks amounts
await expect(stakingManager.connect(delegator).stakeReward(runner3.address)).to.revertedWith('S011');

//delegator claim and delegate
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
expect(delegatorReward1).to.be.gt(0);
const delegatorReward2 = await rewardsDistributor.userRewards(runner2.address, delegator.address);
expect(delegatorReward2).to.be.gt(0);
await expect(
stakingManager.connect(delegator).batchStakeReward([runner.address, runner2.address, runner3.address])
)
.to.emit(rewardsDistributor, 'ClaimRewards')
.withArgs(runner.address, delegator.address, delegatorReward1)
.to.emit(token, 'Transfer')
.withArgs(rewardsDistributor.address, staking.address, delegatorReward1)
.to.emit(rewardsDistributor, 'ClaimRewards')
.withArgs(runner2.address, delegator.address, delegatorReward2)
.to.emit(token, 'Transfer')
.withArgs(rewardsDistributor.address, staking.address, delegatorReward2);

// check userRewards
expect(await rewardsDistributor.userRewards(runner.address, delegator.address)).to.be.eq(0);
// check delegation in staking
const delegation = await staking.delegation(delegator.address, runner.address);
expect(delegation.era).to.be.eq(4);
expect(delegation.valueAt).to.be.eq(delegation1.add(delegatorReward1));
expect(delegation.valueAfter).to.be.eq(delegation1.add(delegatorReward1));
// check delegation in rewardsStaking
expect(await rewardsStaking.getDelegationAmount(delegator.address, runner.address)).to.be.eq(
delegation1.add(delegatorReward1)
);
});
});
});