Skip to content

Commit f37a644

Browse files
committed
refactor: re-stake and unstake if evicted or zero rewards
1 parent 835f590 commit f37a644

3 files changed

Lines changed: 77 additions & 5 deletions

File tree

contracts/interfaces/IStaking.sol

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ pragma solidity ^0.8.30;
55
interface IStaking {
66
enum StakingState {
77
Unstaked,
8-
Staked
8+
Staked,
9+
Evicted
910
}
1011

1112
/// @dev Gets set of agent Ids.
@@ -54,4 +55,11 @@ interface IStaking {
5455
/// @dev Gets available rewards.
5556
/// @return Available rewards amount.
5657
function availableRewards() external view returns (uint256);
58+
59+
/// @dev Checkpoint to allocate rewards up until a current time.
60+
/// @return Staking service Ids (excluding evicted ones within a current epoch).
61+
/// @return Set of reward-eligible service Ids.
62+
/// @return Corresponding set of reward-eligible service rewards.
63+
/// @return Evicted service Ids.
64+
function checkpoint() external returns (uint256[] memory, uint256[] memory, uint256[] memory, uint256[] memory);
5765
}

contracts/l2/ExternalStakingDistributor.sol

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
169169
uint256 stakingDeposit,
170170
uint256 stakedBalance
171171
);
172+
event ExternalServiceRestaked(address indexed sender, address indexed stakingProxy, uint256 indexed serviceId);
172173
event Deployed(uint256 indexed serviceId, address indexed multisig);
173174
event RewardsDistributed(
174175
uint256 indexed serviceId,
@@ -683,9 +684,20 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
683684
// Get staking proxy available rewards amount
684685
uint256 availableRewards = IStaking(stakingProxy).availableRewards();
685686

687+
// Check if service is evicted
688+
IStaking.StakingState stakingState = IStaking(stakingProxy).getStakingState(serviceId);
689+
690+
// Check for unstaked state
691+
if (stakingState == IStaking.StakingState.Unstaked) {
692+
revert ZeroValue();
693+
}
694+
686695
// Check for zero rewards balance and access: whitelisted managing agent or owner
687-
// msg.sender does not matter if rewards are no longer available
688-
if (availableRewards > 0 && !mapManagingAgents[msg.sender] && msg.sender != owner) {
696+
// msg.sender does not matter if rewards are no longer available, or if the service is evicted
697+
if (
698+
stakingState == IStaking.StakingState.Staked && availableRewards > 0
699+
&& !(mapManagingAgents[msg.sender] || msg.sender == owner)
700+
) {
689701
revert UnauthorizedAccount(msg.sender);
690702
}
691703

@@ -760,6 +772,58 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
760772
_locked = 1;
761773
}
762774

775+
/// @dev Re-stakes evicted specified service Id.
776+
/// @param stakingProxy Staking proxy address.
777+
/// @param serviceId Service Id.
778+
function reStake(address stakingProxy, uint256 serviceId) external {
779+
// Reentrancy guard
780+
if (_locked > 1) {
781+
revert ReentrancyGuard();
782+
}
783+
_locked = 2;
784+
785+
// Check for zero address
786+
if (stakingProxy == address(0)) {
787+
revert ZeroAddress();
788+
}
789+
790+
// Check for zero value
791+
if (serviceId == 0) {
792+
revert ZeroValue();
793+
}
794+
795+
// Check if service is evicted
796+
IStaking.StakingState stakingState = IStaking(stakingProxy).getStakingState(serviceId);
797+
798+
// Check for evicted state
799+
if (stakingState != IStaking.StakingState.Evicted) {
800+
revert ZeroValue();
801+
}
802+
803+
// Check for access: curating agent or managing agent, or owner
804+
if (!(mapCuratingAgents[msg.sender] || mapManagingAgents[msg.sender] || msg.sender == owner)) {
805+
revert UnauthorizedAccount(msg.sender);
806+
}
807+
808+
// Unstake service
809+
uint256 reward = IStaking(stakingProxy).unstake(serviceId);
810+
811+
if (reward > 0) {
812+
// Distribute leftover rewards, if not zero
813+
_distributeRewards(stakingProxy, serviceId, reward);
814+
}
815+
816+
// Approve service NFT for re-staking
817+
INFToken(serviceRegistry).approve(stakingProxy, serviceId);
818+
819+
// Stake service
820+
IStaking(stakingProxy).stake(serviceId);
821+
822+
emit ExternalServiceRestaked(msg.sender, stakingProxy, serviceId);
823+
824+
_locked = 1;
825+
}
826+
763827
/// @dev Sets staking proxy types.
764828
/// @param stakingProxies Set of staking proxies.
765829
/// @param configs Corresponding set of staking configs.

doc/agent-workflow.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ contract with the following parameters:
4747
- `_data`: `encodedData` value from `UserRequestForSignature()` event from [AMB (Home)](https://gnosisscan.io/address/0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59#events) contract;
4848
- `_signatures`: from the return value of [`getSignatures()`](https://gnosisscan.io/address/0x7d94ece17e81355326e3359115D4B02411825EdD#readContract#F2) method.
4949

50-
Read full Gnosis guide of how to call execute signatures [here](https://docs.gnosischain.com/bridges/About%20Token%20Bridges/amb-bridge#how-to-call-executesignatures-on-foreign-amb-ethereum).
50+
Read full Gnosis guide on how to call execute signatures [here](https://docs.gnosischain.com/bridges/About%20Token%20Bridges/amb-bridge#how-to-call-executesignatures-on-foreign-amb-ethereum).
5151

5252
#### Base bridge
5353

@@ -126,7 +126,7 @@ Each staked service has a controlling [ActivityModule](../contracts/l2/ActivityM
126126
to all the LST service activity. In order to claim reward tokens and immediately transfer them to [Collector](../contracts/l2/Collector.sol)
127127
contract, agents need to call the `claim()` function, which triggers the `checkpoint()` function call as well of a corresponding `stakingProxy` contract.
128128

129-
Events to track staking proxy addresses, stacked service Ids and their corresponding activity modules in [StakingManager](../contracts/l2/StakingManager.sol) proxy contract:
129+
Events to track staking proxy addresses, staked service Ids and their corresponding activity modules in [StakingManager](../contracts/l2/StakingManager.sol) proxy contract:
130130
```solidity
131131
event Staked(address indexed stakingProxy, uint256 indexed serviceId, address activityModule);
132132
event Unstaked(address indexed stakingProxy, uint256 indexed serviceId, address activityModule);

0 commit comments

Comments
 (0)