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
2 changes: 2 additions & 0 deletions contracts/RewardsBooster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,7 @@ contract RewardsBooster is Initializable, OwnableUpgradeable, IRewardsBooster, S

runnerDeplReward.accRewardsPerToken = accRewardsPerAllocatedToken;
uint256 burnt;
sa.syncOverflowStatus(_runner);
uint256 totalOverflowTime = sa.overAllocationTime(_runner);
(reward, burnt) = _fixRewardsWithMissedLaborAndOverflow(
reward,
Expand Down Expand Up @@ -1078,6 +1079,7 @@ contract RewardsBooster is Initializable, OwnableUpgradeable, IRewardsBooster, S

runnerDeplReward.accRewardsPerToken = accRewardsPerAllocatedToken;
uint256 burnt;
sa.syncOverflowStatus(_runner);
uint256 totalOverflowTime = sa.overAllocationTime(_runner);
(reward, burnt) = _fixRewardsWithMissedLaborAndOverflow(
reward,
Expand Down
35 changes: 29 additions & 6 deletions contracts/StakingAllocation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,7 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea
.getEffectiveTotalStake(_runner);

if (ia.overflowAt == 0 && ia.total < ia.used) {
// new overflow
emit OverAllocationStarted(_runner, block.timestamp);

ia.overflowAt = block.timestamp;
_startOverAllocation(ia, _runner);
} else if (ia.overflowAt != 0 && ia.total >= ia.used) {
// recover from overflow
emit OverAllocationEnded(_runner, block.timestamp, block.timestamp - ia.overflowAt);
Expand All @@ -97,7 +94,7 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea
require(_isAuth(_runner), 'SAL02');
require(
IProjectRegistry(settings.getContractAddress(SQContracts.ProjectRegistry))
.isServiceAvailable(_deployment, _runner),
.isServiceAvailable(_deployment, _runner),
'SAL05'
);

Expand All @@ -114,10 +111,17 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea
_removeAllocation(_deployment, _runner, _amount);
}

function moveAllocation(bytes32 _deploymentFrom, bytes32 _deploymentTo, address _runner, uint256 _amount) external {
function moveAllocation(
bytes32 _deploymentFrom,
bytes32 _deploymentTo,
address _runner,
uint256 _amount
) external {
require(_isAuth(_runner), 'SAL02');
require(allocatedTokens[_runner][_deploymentFrom] >= _amount, 'SAL04');
require(_deploymentFrom != _deploymentTo, 'SAL07');
RunnerAllocation storage ia = _runnerAllocations[_runner];
require(ia.total >= ia.used, 'SAL03');

_removeAllocation(_deploymentFrom, _runner, _amount);
_addAllocation(_deploymentTo, _runner, _amount);
Expand Down Expand Up @@ -176,12 +180,19 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea
return _runnerAllocations[_runner];
}

function syncOverflowStatus(address _runner) external override {
_syncOverflowStatus(_runner);
}

/**
* @notice this returns the accumulated overflowTime of given runner
*/
function overAllocationTime(address _runner) external view returns (uint256) {
RunnerAllocation memory ia = _runnerAllocations[_runner];
if (ia.total < ia.used) {
if (ia.overflowAt == 0) {
return ia.overflowTime;
}
return ia.overflowTime + block.timestamp - ia.overflowAt;
} else {
return ia.overflowTime;
Expand All @@ -199,4 +210,16 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea
address controller = indexerRegistry.getController(_runner);
return msg.sender == _runner || msg.sender == controller;
}

function _syncOverflowStatus(address _runner) private {
RunnerAllocation storage ia = _runnerAllocations[_runner];
if (ia.overflowAt == 0 && ia.total < ia.used) {
_startOverAllocation(ia, _runner);
}
}

function _startOverAllocation(RunnerAllocation storage ia, address _runner) private {
emit OverAllocationStarted(_runner, block.timestamp);
ia.overflowAt = block.timestamp;
}
}
2 changes: 2 additions & 0 deletions contracts/interfaces/IStakingAllocation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ interface IStakingAllocation {

function allocatedTokens(address _runner, bytes32 _deployment) external view returns (uint256);

function syncOverflowStatus(address _runner) external;

function runnerAllocation(address _runner) external view returns (RunnerAllocation memory);

function overAllocationTime(address _runner) external view returns (uint256);
Expand Down
13 changes: 13 additions & 0 deletions publish/ABI/StakingAllocation.json
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_runner",
"type": "address"
}
],
"name": "syncOverflowStatus",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
32 changes: 22 additions & 10 deletions test/StakingAllocation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ describe('StakingAllocation Contract', () => {
expect(da0).to.eq(etherParse('14000'));
expect(da1).to.eq(etherParse('1000'));


await expect(
stakingAllocation.connect(runner0).addAllocation(deploymentIds[1], runner0.address, etherParse('5001'))
).to.be.revertedWith('SAL03');
Expand All @@ -257,7 +256,6 @@ describe('StakingAllocation Contract', () => {
await checkAllocation(runner1, etherParse('9000'), etherParse('10000'), true, false);
await timeTravel(10);


await stakingAllocation
.connect(runner1)
.removeAllocation(deploymentIds[0], runner1.address, etherParse('500'));
Expand All @@ -268,14 +266,17 @@ describe('StakingAllocation Contract', () => {
await checkAllocation(runner1, etherParse('9000'), etherParse('9000'), false, true);

await expect(
stakingAllocation.connect(runner1).moveAllocation(deploymentIds[0], deploymentIds[0], runner1.address, etherParse('1000'))
stakingAllocation
.connect(runner1)
.moveAllocation(deploymentIds[0], deploymentIds[0], runner1.address, etherParse('1000'))
).to.revertedWith('SAL07');

await expect(
stakingAllocation.connect(runner1).moveAllocation(deploymentIds[0], deploymentIds[1], runner1.address, etherParse('1199000'))
stakingAllocation
.connect(runner1)
.moveAllocation(deploymentIds[0], deploymentIds[1], runner1.address, etherParse('1199000'))
).to.revertedWith('SAL04');


await stakingAllocation
.connect(runner1)
.moveAllocation(deploymentIds[0], deploymentIds[1], runner1.address, etherParse('1000'));
Expand All @@ -292,10 +293,7 @@ describe('StakingAllocation Contract', () => {
expect(await stakingAllocation.allocatedTokens(runner1.address, deploymentIds[0])).to.eq(
etherParse('9000')
);
expect(await stakingAllocation.allocatedTokens(runner1.address, deploymentIds[1])).to.eq(
etherParse('0')
);

expect(await stakingAllocation.allocatedTokens(runner1.address, deploymentIds[1])).to.eq(etherParse('0'));
});

it('add allocation to a stopped project', async () => {
Expand All @@ -310,7 +308,6 @@ describe('StakingAllocation Contract', () => {

await stakingAllocation.connect(runner0).addAllocation(deploymentId0, runner0.address, etherParse('5000'));
await checkAllocation(runner0, etherParse('10000'), etherParse('5000'), false, false);

});

it('over-allocate and recover', async () => {
Expand Down Expand Up @@ -351,6 +348,21 @@ describe('StakingAllocation Contract', () => {
).to.revertedWith('SAL03');
});

it('blocks move allocation when runner is over-allocated', async () => {
await stakingAllocation
.connect(runner0)
.addAllocation(deploymentIds[0], runner0.address, etherParse('10000'));

await stakingManager.connect(runner0).unstake(runner0.address, etherParse('1000'));
await applyStaking(runner0, runner0);

await expect(
stakingAllocation
.connect(runner0)
.moveAllocation(deploymentIds[0], deploymentIds[1], runner0.address, etherParse('1000'))
).to.be.revertedWith('SAL03');
});

it('remove allocation when stop service', async () => {
await checkAllocation(runner0, etherParse('10000'), 0, false, false);
await stakingManager.connect(runner0).stake(runner0.address, etherParse('10000'));
Expand Down