Skip to content

Commit

Permalink
Permissionless method to force unstake legacy stakes TokenStaking
Browse files Browse the repository at this point in the history
  • Loading branch information
vzotova committed Sep 21, 2023
1 parent 05a30d1 commit 0b123a6
Show file tree
Hide file tree
Showing 3 changed files with 384 additions and 1 deletion.
75 changes: 75 additions & 0 deletions contracts/staking/TokenStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,15 @@ contract TokenStaking is Initializable, IStaking, Checkpoints {
}
}

/// @notice Involuntary decrease authorization for all application up to T
/// stake amount for all staking providers in the list.
/// Sets cached legacy stake amount to 0. Can be called by anyone
function forceUnstakeLegacy(address[] memory _stakingProviders) external {
for (uint256 i = 0; i < _stakingProviders.length; i++) {
forceUnstakeLegacy(_stakingProviders[i]);
}
}

//
//
// Keeping information in sync
Expand Down Expand Up @@ -1004,6 +1013,72 @@ contract TokenStaking is Initializable, IStaking, Checkpoints {
);
}

/// @notice Involuntary decrease authorization for all application up to T
/// stake amount. Sets cached legacy stake amount to 0.
/// Can be called by anyone
function forceUnstakeLegacy(address stakingProvider) public {
StakingProviderInfo storage stakingProviderStruct = stakingProviders[
stakingProvider
];
uint96 legacyStake = stakingProviderStruct.keepInTStake +
stakingProviderStruct.nuInTStake;
require(legacyStake > 0, "No legacy stake");

// similar to authorizationDecrease method
uint256 applicationsToDelete = 0;
for (
uint256 i = 0;
i < stakingProviderStruct.authorizedApplications.length;
i++
) {
address authorizedApplication = stakingProviderStruct
.authorizedApplications[i];
AppAuthorization storage authorization = stakingProviderStruct
.authorizations[authorizedApplication];
uint96 fromAmount = authorization.authorized;

if (fromAmount <= stakingProviderStruct.tStake) {
continue;
}
authorization.authorized = stakingProviderStruct.tStake;

bool successful = true;
//slither-disable-next-line calls-loop
try
IApplication(authorizedApplication)
.involuntaryAuthorizationDecrease{
gas: GAS_LIMIT_AUTHORIZATION_DECREASE
}(stakingProvider, fromAmount, authorization.authorized)
{} catch {
successful = false;
}
if (authorization.deauthorizing > authorization.authorized) {
authorization.deauthorizing = authorization.authorized;
}
emit AuthorizationInvoluntaryDecreased(
stakingProvider,
authorizedApplication,
fromAmount,
authorization.authorized,
successful
);
if (authorization.authorized == 0) {
applicationsToDelete++;
}
}
if (applicationsToDelete > 0) {
cleanAuthorizedApplications(
stakingProviderStruct,
applicationsToDelete
);
}

emit Unstaked(stakingProvider, legacyStake);
stakingProviderStruct.keepInTStake = 0;
stakingProviderStruct.nuInTStake = 0;
decreaseStakeCheckpoint(stakingProvider, legacyStake);
}

/// @notice Returns minimum possible stake for T, KEEP or NU in T denomination
/// @dev For example, suppose the given staking provider has 10 T, 20 T worth
/// of KEEP, and 30 T worth of NU all staked, and the maximum
Expand Down
10 changes: 9 additions & 1 deletion contracts/test/TokenStakingTestSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,16 @@ contract LegacyTokenStaking is TokenStaking {
];
AppAuthorization storage authorization = stakingProviderStruct
.authorizations[application];
stakingProviderStruct.authorizedApplications.push(application);
uint96 fromAmount = authorization.authorized;
if (fromAmount == 0) {
stakingProviderStruct.authorizedApplications.push(application);
}
authorization.authorized += amount;
IApplication(application).authorizationIncreased(
stakingProvider,
fromAmount,
authorization.authorized
);
}

function setLegacyStakingProvider(
Expand Down
Loading

0 comments on commit 0b123a6

Please sign in to comment.