Skip to content

Commit 9f9fd34

Browse files
authored
add batchStakeReward() (#442)
* add batchStakeReward()
1 parent 63e8d1b commit 9f9fd34

3 files changed

Lines changed: 131 additions & 52 deletions

File tree

contracts/StakingManager.sol

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,22 +118,38 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable {
118118
// can not be called when the node operator hasn't collected latest rewards
119119
// can not be called when the node operator is unregistered
120120
// @param _runner the node operator address
121-
function delegateReward(address _runner) external {
121+
function stakeReward(address _runner) external {
122+
_stakeReward(msg.sender, _runner, false);
123+
}
124+
125+
// @dev batch version of stakeReward
126+
function batchStakeReward(address[] calldata _runners) external {
127+
for (uint256 i = 0; i < _runners.length; i++) {
128+
_stakeReward(msg.sender, _runners[i], true);
129+
}
130+
}
131+
132+
function _stakeReward(address _staker, address _runner, bool _skipError) internal {
122133
Staking staking = Staking(settings.getContractAddress(SQContracts.Staking));
123-
address staker = msg.sender;
124134
// runner should be valid in the following era.
135+
if (_skipError && this.getAfterDelegationAmount(_runner, _runner) == 0) {
136+
return;
137+
}
125138
require(this.getAfterDelegationAmount(_runner, _runner) > 0, 'S012');
126139
IRewardsDistributor rewardsDistributor = IRewardsDistributor(
127140
settings.getContractAddress(SQContracts.RewardsDistributor)
128141
);
129142
// rewards sent to Staking from rewardsDistributor
130-
uint256 rewards = rewardsDistributor.claimForDelegate(_runner, staker);
143+
uint256 rewards = rewardsDistributor.claimForDelegate(_runner, _staker);
144+
if (_skipError && rewards == 0) {
145+
return;
146+
}
131147
require(rewards > 0, 'S011');
132-
staking.addDelegation(staker, _runner, rewards, true);
148+
staking.addDelegation(_staker, _runner, rewards, true);
133149
IRewardsStaking rewardsStaking = IRewardsStaking(
134150
settings.getContractAddress(SQContracts.RewardsStaking)
135151
);
136-
rewardsStaking.applyRedelegation(_runner, staker);
152+
rewardsStaking.applyRedelegation(_runner, _staker);
137153
}
138154

139155
function cancelUnbonding(uint256 unbondReqId) external {

publish/ABI/StakingManager.json

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,30 +34,25 @@
3434
{
3535
"inputs": [
3636
{
37-
"internalType": "uint256",
38-
"name": "unbondReqId",
39-
"type": "uint256"
37+
"internalType": "address[]",
38+
"name": "_runners",
39+
"type": "address[]"
4040
}
4141
],
42-
"name": "cancelUnbonding",
42+
"name": "batchStakeReward",
4343
"outputs": [],
4444
"stateMutability": "nonpayable",
4545
"type": "function"
4646
},
4747
{
4848
"inputs": [
49-
{
50-
"internalType": "address",
51-
"name": "_runner",
52-
"type": "address"
53-
},
5449
{
5550
"internalType": "uint256",
56-
"name": "_amount",
51+
"name": "unbondReqId",
5752
"type": "uint256"
5853
}
5954
],
60-
"name": "delegate",
55+
"name": "cancelUnbonding",
6156
"outputs": [],
6257
"stateMutability": "nonpayable",
6358
"type": "function"
@@ -68,9 +63,14 @@
6863
"internalType": "address",
6964
"name": "_runner",
7065
"type": "address"
66+
},
67+
{
68+
"internalType": "uint256",
69+
"name": "_amount",
70+
"type": "uint256"
7171
}
7272
],
73-
"name": "delegateReward",
73+
"name": "delegate",
7474
"outputs": [],
7575
"stateMutability": "nonpayable",
7676
"type": "function"
@@ -363,6 +363,19 @@
363363
"stateMutability": "nonpayable",
364364
"type": "function"
365365
},
366+
{
367+
"inputs": [
368+
{
369+
"internalType": "address",
370+
"name": "_runner",
371+
"type": "address"
372+
}
373+
],
374+
"name": "stakeReward",
375+
"outputs": [],
376+
"stateMutability": "nonpayable",
377+
"type": "function"
378+
},
366379
{
367380
"inputs": [
368381
{

test/RewardsDistributer.test.ts

Lines changed: 85 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { acceptPlan, addInstantRewards, etherParse, eventFrom, startNewEra, time
2121
import { deployContracts } from './setup';
2222

2323
describe('RewardsDistributor Contract', () => {
24-
let root, runner, consumer, delegator, delegator2;
24+
let root, runner, runner2, runner3, consumer, delegator, delegator2;
2525

2626
let token: ERC20;
2727
let staking: Staking;
@@ -72,7 +72,7 @@ describe('RewardsDistributor Contract', () => {
7272

7373
const deployer = () => deployContracts(root, runner);
7474
before(async () => {
75-
[root, runner, consumer, delegator, delegator2] = await ethers.getSigners();
75+
[root, runner, runner2, runner3, consumer, delegator, delegator2] = await ethers.getSigners();
7676
});
7777

7878
beforeEach(async () => {
@@ -102,10 +102,13 @@ describe('RewardsDistributor Contract', () => {
102102
//register an new Indexer with Initial Commission Rate: 10% and Initial Staking Amount: 1000
103103
//moved to era 2
104104
await registerIndexer(root, runner, runnerInitialStake, runnerCr);
105+
await registerIndexer(root, runner2, runnerInitialStake, runnerCr);
106+
await registerIndexer(root, runner3, runnerInitialStake, runnerCr);
105107
await registerIndexer(root, root, runnerInitialStake, runnerCr);
106108
await projectRegistry.createProject(METADATA_HASH, VERSION, DEPLOYMENT_ID, 0);
107109
// wallet_0 start project
108110
await projectRegistry.connect(runner).startService(DEPLOYMENT_ID);
111+
await projectRegistry.connect(runner2).startService(DEPLOYMENT_ID);
109112
await projectRegistry.connect(root).startService(DEPLOYMENT_ID);
110113
});
111114

@@ -1009,11 +1012,15 @@ describe('RewardsDistributor Contract', () => {
10091012
await rewardsStaking.setRunnerStakeWeight(2e6);
10101013
//a 30 days agreement with 400 rewards come in at Era2
10111014
await acceptPlan(runner, consumer, 30, etherParse('3'), DEPLOYMENT_ID, token, planManager);
1015+
await acceptPlan(runner2, consumer, 30, etherParse('3'), DEPLOYMENT_ID, token, planManager);
10121016
await acceptPlan(root, consumer, 30, etherParse('3'), DEPLOYMENT_ID, token, planManager);
10131017
await staking.setIndexerLeverageLimit(20);
10141018
await token.transfer(delegator.address, delegation1);
10151019
await token.connect(delegator).increaseAllowance(staking.address, delegation1);
10161020
await stakingManager.connect(delegator).delegate(runner.address, delegation1);
1021+
await token.transfer(delegator.address, delegation2);
1022+
await token.connect(delegator).increaseAllowance(staking.address, delegation2);
1023+
await stakingManager.connect(delegator).delegate(runner2.address, delegation2);
10171024
await token.transfer(delegator2.address, delegation2);
10181025
await token.connect(delegator2).increaseAllowance(staking.address, delegation2);
10191026
await stakingManager.connect(delegator2).delegate(runner.address, delegation2);
@@ -1031,7 +1038,7 @@ describe('RewardsDistributor Contract', () => {
10311038
//delegator claim and delegate
10321039
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
10331040
expect(delegatorReward1).to.be.gt(0);
1034-
await expect(stakingManager.connect(delegator).delegateReward(runner.address))
1041+
await expect(stakingManager.connect(delegator).stakeReward(runner.address))
10351042
.to.emit(rewardsDistributor, 'ClaimRewards')
10361043
.withArgs(runner.address, delegator.address, delegatorReward1)
10371044
.to.emit(token, 'Transfer')
@@ -1061,7 +1068,7 @@ describe('RewardsDistributor Contract', () => {
10611068
//delegator claim and delegate
10621069
const rewards1 = await rewardsDistributor.userRewards(runner.address, runner.address);
10631070
expect(rewards1).to.be.gt(0);
1064-
await expect(stakingManager.connect(runner).delegateReward(runner.address))
1071+
await expect(stakingManager.connect(runner).stakeReward(runner.address))
10651072
.to.emit(rewardsDistributor, 'ClaimRewards')
10661073
.withArgs(runner.address, runner.address, rewards1)
10671074
.to.emit(token, 'Transfer')
@@ -1101,7 +1108,7 @@ describe('RewardsDistributor Contract', () => {
11011108
//delegator claim and delegate
11021109
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
11031110
expect(delegatorReward1).to.be.gt(0);
1104-
await expect(stakingManager.connect(delegator).delegateReward(runner.address))
1111+
await expect(stakingManager.connect(delegator).stakeReward(runner.address))
11051112
.to.emit(rewardsDistributor, 'ClaimRewards')
11061113
.withArgs(runner.address, delegator.address, delegatorReward1)
11071114
.to.emit(token, 'Transfer')
@@ -1137,7 +1144,7 @@ describe('RewardsDistributor Contract', () => {
11371144
//delegator claim and delegate
11381145
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
11391146
expect(delegatorReward1).to.be.gt(0);
1140-
await expect(stakingManager.connect(delegator).delegateReward(runner.address))
1147+
await expect(stakingManager.connect(delegator).stakeReward(runner.address))
11411148
.to.emit(rewardsDistributor, 'ClaimRewards')
11421149
.withArgs(runner.address, delegator.address, delegatorReward1)
11431150
.to.emit(token, 'Transfer')
@@ -1170,7 +1177,7 @@ describe('RewardsDistributor Contract', () => {
11701177
await rewardsDistributor.connect(delegator).claim(runner.address);
11711178
expect(await rewardsDistributor.userRewards(runner.address, delegator.address)).to.be.eq(0);
11721179

1173-
await expect(stakingManager.connect(delegator).delegateReward(runner.address)).to.revertedWith('S011');
1180+
await expect(stakingManager.connect(delegator).stakeReward(runner.address)).to.revertedWith('S011');
11741181
});
11751182

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

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

1194-
//move to next era
1195-
await startNewEra(eraManager);
1196-
await rewardsHelper.connect(runner).indexerCatchup(runner.address);
1197-
1198-
//delegator claim and delegate
1199-
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
1200-
expect(delegatorReward1).to.be.gt(0);
1201-
await expect(stakingManager.connect(delegator).delegateReward(runner.address))
1202-
.to.emit(rewardsDistributor, 'ClaimRewards')
1203-
.withArgs(runner.address, delegator.address, delegatorReward1)
1204-
.to.emit(token, 'Transfer')
1205-
.withArgs(rewardsDistributor.address, staking.address, delegatorReward1);
1206-
1207-
// check userRewards
1208-
expect(await rewardsDistributor.userRewards(runner.address, delegator.address)).to.be.eq(0);
1209-
// check delegation in staking
1210-
const delegation = await staking.delegation(delegator.address, runner.address);
1211-
expect(delegation.era).to.be.eq(4);
1212-
expect(delegation.valueAt).to.be.eq(delegation1.add(delegatorReward1));
1213-
expect(delegation.valueAfter).to.be.eq(delegation1.add(delegatorReward1));
1214-
// check delegation in rewardsStaking
1215-
expect(await rewardsStaking.getDelegationAmount(delegator.address, runner.address)).to.be.eq(
1216-
delegation1.add(delegatorReward1)
1217-
);
1218-
const effectiveTotalStake = await stakingManager.getEffectiveTotalStake(runner.address);
1219-
expect(effectiveTotalStake).to.eq(runnerStake.valueAt.mul(leverageLimit));
1201+
// //move to next era
1202+
// await startNewEra(eraManager);
1203+
// await rewardsHelper.connect(runner).indexerCatchup(runner.address);
1204+
//
1205+
// //delegator claim and delegate
1206+
// const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
1207+
// expect(delegatorReward1).to.be.gt(0);
1208+
// await expect(stakingManager.connect(delegator).stakeReward(runner.address))
1209+
// .to.emit(rewardsDistributor, 'ClaimRewards')
1210+
// .withArgs(runner.address, delegator.address, delegatorReward1)
1211+
// .to.emit(token, 'Transfer')
1212+
// .withArgs(rewardsDistributor.address, staking.address, delegatorReward1);
1213+
//
1214+
// // check userRewards
1215+
// expect(await rewardsDistributor.userRewards(runner.address, delegator.address)).to.be.eq(0);
1216+
// // check delegation in staking
1217+
// const delegation = await staking.delegation(delegator.address, runner.address);
1218+
// expect(delegation.era).to.be.eq(4);
1219+
// expect(delegation.valueAt).to.be.eq(delegation1.add(delegatorReward1));
1220+
// expect(delegation.valueAfter).to.be.eq(delegation1.add(delegatorReward1));
1221+
// // check delegation in rewardsStaking
1222+
// expect(await rewardsStaking.getDelegationAmount(delegator.address, runner.address)).to.be.eq(
1223+
// delegation1.add(delegatorReward1)
1224+
// );
1225+
// const effectiveTotalStake = await stakingManager.getEffectiveTotalStake(runner.address);
1226+
// expect(effectiveTotalStake).to.eq(runnerStake.valueAt.mul(leverageLimit));
12201227
});
12211228

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

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

12751282
// delegator claim and delegate
1276-
await expect(stakingManager.connect(delegator).delegateReward(runner.address)).to.be.revertedWith('S012');
1283+
await expect(stakingManager.connect(delegator).stakeReward(runner.address)).to.be.revertedWith('S012');
1284+
});
1285+
1286+
// earn rewards from runner, runner2
1287+
// no rewards from runner3
1288+
it('should allow delegator to batch claim collect and delegate', async () => {
1289+
expect(await eraManager.eraNumber()).to.be.eq(3);
1290+
expect((await rewardsDistributor.getRewardInfo(runner.address)).lastClaimEra).to.be.eq(2);
1291+
//move to next era
1292+
await startNewEra(eraManager);
1293+
await rewardsHelper.connect(runner).indexerCatchup(runner.address);
1294+
await rewardsHelper.connect(runner2).indexerCatchup(runner2.address);
1295+
1296+
// single stakeReward checks amounts
1297+
await expect(stakingManager.connect(delegator).stakeReward(runner3.address)).to.revertedWith('S011');
1298+
1299+
//delegator claim and delegate
1300+
const delegatorReward1 = await rewardsDistributor.userRewards(runner.address, delegator.address);
1301+
expect(delegatorReward1).to.be.gt(0);
1302+
const delegatorReward2 = await rewardsDistributor.userRewards(runner2.address, delegator.address);
1303+
expect(delegatorReward2).to.be.gt(0);
1304+
await expect(
1305+
stakingManager.connect(delegator).batchStakeReward([runner.address, runner2.address, runner3.address])
1306+
)
1307+
.to.emit(rewardsDistributor, 'ClaimRewards')
1308+
.withArgs(runner.address, delegator.address, delegatorReward1)
1309+
.to.emit(token, 'Transfer')
1310+
.withArgs(rewardsDistributor.address, staking.address, delegatorReward1)
1311+
.to.emit(rewardsDistributor, 'ClaimRewards')
1312+
.withArgs(runner2.address, delegator.address, delegatorReward2)
1313+
.to.emit(token, 'Transfer')
1314+
.withArgs(rewardsDistributor.address, staking.address, delegatorReward2);
1315+
1316+
// check userRewards
1317+
expect(await rewardsDistributor.userRewards(runner.address, delegator.address)).to.be.eq(0);
1318+
// check delegation in staking
1319+
const delegation = await staking.delegation(delegator.address, runner.address);
1320+
expect(delegation.era).to.be.eq(4);
1321+
expect(delegation.valueAt).to.be.eq(delegation1.add(delegatorReward1));
1322+
expect(delegation.valueAfter).to.be.eq(delegation1.add(delegatorReward1));
1323+
// check delegation in rewardsStaking
1324+
expect(await rewardsStaking.getDelegationAmount(delegator.address, runner.address)).to.be.eq(
1325+
delegation1.add(delegatorReward1)
1326+
);
12771327
});
12781328
});
12791329
});

0 commit comments

Comments
 (0)