TokenStaking

TokenStaking

TokenStaking is the main staking contract of the Threshold Network. Apart from the basic usage of enabling T stakes, it also acts as a sort of "meta-staking" contract, accepting existing legacy NU/KEEP stakes. Additionally, it serves as application manager for the apps that run on the Threshold Network. Note that legacy NU/KEEP staking contracts see TokenStaking as an application (e.g., slashing is requested by TokenStaking and performed by the legacy contracts).

TokenStaking is upgradeable, using OpenZeppelin's Upgradeability framework. As such, it is required to satisfy OZ's guidelines, like restrictions on constructors, immutable variables, base contracts and libraries. See https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable

ApplicationStatus

enum ApplicationStatus {
  NOT_APPROVED,
  APPROVED,
  PAUSED,
  DISABLED
}

StakingProviderInfo

struct StakingProviderInfo {
  uint96 nuInTStake;
  address owner;
  uint96 keepInTStake;
  address payable beneficiary;
  uint96 tStake;
  address authorizer;
  mapping(address => struct TokenStaking.AppAuthorization) authorizations;
  address[] authorizedApplications;
  uint256 startStakingTimestamp;
}

AppAuthorization

struct AppAuthorization {
  uint96 authorized;
  uint96 deauthorizing;
}

ApplicationInfo

struct ApplicationInfo {
  enum TokenStaking.ApplicationStatus status;
  address panicButton;
}

SlashingEvent

struct SlashingEvent {
  address stakingProvider;
  uint96 amount;
}

SLASHING_REWARD_PERCENT

uint256 SLASHING_REWARD_PERCENT

MIN_STAKE_TIME

uint256 MIN_STAKE_TIME

GAS_LIMIT_AUTHORIZATION_DECREASE

uint256 GAS_LIMIT_AUTHORIZATION_DECREASE

CONVERSION_DIVISOR

uint256 CONVERSION_DIVISOR

token

contract T token

keepStakingContract

contract IKeepTokenStaking keepStakingContract

keepStake

contract KeepStake keepStake

nucypherStakingContract

contract INuCypherStakingEscrow nucypherStakingContract

keepRatio

uint256 keepRatio

nucypherRatio

uint256 nucypherRatio

governance

address governance

minTStakeAmount

uint96 minTStakeAmount

authorizationCeiling

uint256 authorizationCeiling

stakeDiscrepancyPenalty

uint96 stakeDiscrepancyPenalty

stakeDiscrepancyRewardMultiplier

uint256 stakeDiscrepancyRewardMultiplier

notifiersTreasury

uint256 notifiersTreasury

notificationReward

uint256 notificationReward

stakingProviders

mapping(address => struct TokenStaking.StakingProviderInfo) stakingProviders

applicationInfo

mapping(address => struct TokenStaking.ApplicationInfo) applicationInfo

applications

address[] applications

slashingQueue

struct TokenStaking.SlashingEvent[] slashingQueue

slashingQueueIndex

uint256 slashingQueueIndex

Staked

event Staked(enum IStaking.StakeType stakeType, address owner, address stakingProvider, address beneficiary, address authorizer, uint96 amount)

MinimumStakeAmountSet

event MinimumStakeAmountSet(uint96 amount)

ApplicationStatusChanged

event ApplicationStatusChanged(address application, enum TokenStaking.ApplicationStatus newStatus)

AuthorizationIncreased

event AuthorizationIncreased(address stakingProvider, address application, uint96 fromAmount, uint96 toAmount)

AuthorizationDecreaseRequested

event AuthorizationDecreaseRequested(address stakingProvider, address application, uint96 fromAmount, uint96 toAmount)

AuthorizationDecreaseApproved

event AuthorizationDecreaseApproved(address stakingProvider, address application, uint96 fromAmount, uint96 toAmount)

AuthorizationInvoluntaryDecreased

event AuthorizationInvoluntaryDecreased(address stakingProvider, address application, uint96 fromAmount, uint96 toAmount, bool successfulCall)

PanicButtonSet

event PanicButtonSet(address application, address panicButton)

AuthorizationCeilingSet

event AuthorizationCeilingSet(uint256 ceiling)

ToppedUp

event ToppedUp(address stakingProvider, uint96 amount)

Unstaked

event Unstaked(address stakingProvider, uint96 amount)

TokensSeized

event TokensSeized(address stakingProvider, uint96 amount, bool discrepancy)

StakeDiscrepancyPenaltySet

event StakeDiscrepancyPenaltySet(uint96 penalty, uint256 rewardMultiplier)

NotificationRewardSet

event NotificationRewardSet(uint96 reward)

NotificationRewardPushed

event NotificationRewardPushed(uint96 reward)

NotificationRewardWithdrawn

event NotificationRewardWithdrawn(address recipient, uint96 amount)

NotifierRewarded

event NotifierRewarded(address notifier, uint256 amount)

SlashingProcessed

event SlashingProcessed(address caller, uint256 count, uint256 tAmount)

OwnerRefreshed

event OwnerRefreshed(address stakingProvider, address oldOwner, address newOwner)

GovernanceTransferred

event GovernanceTransferred(address oldGovernance, address newGovernance)

onlyGovernance

modifier onlyGovernance()

onlyPanicButtonOf

modifier onlyPanicButtonOf(address application)

onlyAuthorizerOf

modifier onlyAuthorizerOf(address stakingProvider)

onlyOwnerOrStakingProvider

modifier onlyOwnerOrStakingProvider(address stakingProvider)

onlyOwnerOf

modifier onlyOwnerOf(address stakingProvider)

constructor

constructor(contract T _token, contract IKeepTokenStaking _keepStakingContract, contract INuCypherStakingEscrow _nucypherStakingContract, contract VendingMachine _keepVendingMachine, contract VendingMachine _nucypherVendingMachine, contract KeepStake _keepStake) public

Parameters

NameTypeDescription

_token

contract T

Address of T token contract

_keepStakingContract

contract IKeepTokenStaking

Address of Keep staking contract

_nucypherStakingContract

contract INuCypherStakingEscrow

Address of NuCypher staking contract

_keepVendingMachine

contract VendingMachine

Address of Keep vending machine

_nucypherVendingMachine

contract VendingMachine

Address of NuCypher vending machine

_keepStake

contract KeepStake

Address of Keep contract with grant owners

initialize

function initialize() external

stake

function stake(address stakingProvider, address payable beneficiary, address authorizer, uint96 amount) external

Creates a delegation with msg.sender owner with the given staking provider, beneficiary, and authorizer. Transfers the given amount of T to the staking contract.

The owner of the delegation needs to have the amount approved to transfer to the staking contract.

stakeKeep

function stakeKeep(address stakingProvider) external

Copies delegation from the legacy KEEP staking contract to T staking contract. No tokens are transferred. Caches the active stake amount from KEEP staking contract. Can be called by anyone.

The staking provider in T staking contract is the legacy KEEP staking contract operator.

stakeNu

function stakeNu(address stakingProvider, address payable beneficiary, address authorizer) external

Copies delegation from the legacy NU staking contract to T staking contract, additionally appointing beneficiary and authorizer roles. Caches the amount staked in NU staking contract. Can be called only by the original delegation owner.

setMinimumStakeAmount

function setMinimumStakeAmount(uint96 amount) external

Allows the Governance to set the minimum required stake amount. This amount is required to protect against griefing the staking contract and individual applications are allowed to require higher minimum stakes if necessary.

Staking providers are not required to maintain a minimum T stake all the time. 24 hours after the delegation, T stake can be reduced below the minimum stake. The minimum stake in the staking contract is just to protect against griefing stake operation. Please note that each application may have its own minimum authorization though and the authorization can not be higher than the stake.

approveApplication

function approveApplication(address application) external

Allows the Governance to approve the particular application before individual stake authorizers are able to authorize it.

increaseAuthorization

function increaseAuthorization(address stakingProvider, address application, uint96 amount) external

Increases the authorization of the given staking provider for the given application by the given amount. Can only be called by the given staking provider’s authorizer.

Calls authorizationIncreased callback on the given application to notify the application about authorization change. See IApplication.

requestAuthorizationDecrease

function requestAuthorizationDecrease(address stakingProvider) external

Requests decrease of all authorizations for the given staking provider on all applications by all authorized amount. It may not change the authorized amount immediatelly. When it happens depends on the application. Can only be called by the given staking provider’s authorizer. Overwrites pending authorization decrease for the given staking provider and application.

Calls authorizationDecreaseRequested callback for each authorized application. See IApplication.

approveAuthorizationDecrease

function approveAuthorizationDecrease(address stakingProvider) external returns (uint96)

Called by the application at its discretion to approve the previously requested authorization decrease request. Can only be called by the application that was previously requested to decrease the authorization for that staking provider. Returns resulting authorized amount for the application.

forceDecreaseAuthorization

function forceDecreaseAuthorization(address stakingProvider, address application) external

Decreases the authorization for the given stakingProvider on the given disabled application, for all authorized amount. Can be called by anyone.

pauseApplication

function pauseApplication(address application) external

Pauses the given application’s eligibility to slash stakes. Besides that stakers can't change authorization to the application. Can be called only by the Panic Button of the particular application. The paused application can not slash stakes until it is approved again by the Governance using approveApplication function. Should be used only in case of an emergency.

disableApplication

function disableApplication(address application) external

Disables the given application. The disabled application can't slash stakers. Also stakers can't increase authorization to that application but can decrease without waiting by calling forceDecreaseAuthorization at any moment. Can be called only by the governance. The disabled application can't be approved again. Should be used only in case of an emergency.

setPanicButton

function setPanicButton(address application, address panicButton) external

Sets the Panic Button role for the given application to the provided address. Can only be called by the Governance. If the Panic Button for the given application should be disabled, the role address should be set to 0x0 address.

setAuthorizationCeiling

function setAuthorizationCeiling(uint256 ceiling) external

Sets the maximum number of applications one staking provider can have authorized. Used to protect against DoSing slashing queue. Can only be called by the Governance.

topUp

function topUp(address stakingProvider, uint96 amount) external

Increases the amount of the stake for the given staking provider.

The sender of this transaction needs to have the amount approved to transfer to the staking contract.

topUpKeep

function topUpKeep(address stakingProvider) external

Propagates information about stake top-up from the legacy KEEP staking contract to T staking contract. Can be called only by the owner or the staking provider.

topUpNu

function topUpNu(address stakingProvider) external

Propagates information about stake top-up from the legacy NU staking contract to T staking contract. Can be called only by the owner or the staking provider.

unstakeT

function unstakeT(address stakingProvider, uint96 amount) external

Reduces the liquid T stake amount by the provided amount and withdraws T to the owner. Reverts if there is at least one authorization higher than the sum of the legacy stake and remaining liquid T stake or if the unstake amount is higher than the liquid T stake amount. Can be called only by the owner or the staking provider. Can only be called when 24h passed since the stake has been delegated.

unstakeKeep

function unstakeKeep(address stakingProvider) external

Sets the legacy KEEP staking contract active stake amount cached in T staking contract to 0. Reverts if the amount of liquid T staked in T staking contract is lower than the highest application authorization. This function allows to unstake from KEEP staking contract and still being able to operate in T network and earning rewards based on the liquid T staked. Can be called only by the delegation owner or the staking provider. Can only be called when 24h passed since the stake has been delegated.

This function (or unstakeAll) must be called before undelegate/undelegateAt in Keep staking contract. Otherwise provider can be slashed by notifyKeepStakeDiscrepancy method.

unstakeNu

function unstakeNu(address stakingProvider, uint96 amount) external

Reduces cached legacy NU stake amount by the provided amount. Reverts if there is at least one authorization higher than the sum of remaining legacy NU stake and liquid T stake for that staking provider or if the untaked amount is higher than the cached legacy stake amount. If succeeded, the legacy NU stake can be partially or fully undelegated on the legacy staking contract. This function allows to unstake from NU staking contract and still being able to operate in T network and earning rewards based on the liquid T staked. Can be called only by the delegation owner or the staking provider. Can only be called when 24h passed since the stake has been delegated.

This function (or unstakeAll) must be called before withdraw in NuCypher staking contract. Otherwise NU tokens can't be unlocked.

Parameters

NameTypeDescription

stakingProvider

address

Staking provider address

amount

uint96

Amount of NU to unstake in T denomination

unstakeAll

function unstakeAll(address stakingProvider) external

Sets cached legacy stake amount to 0, sets the liquid T stake amount to 0 and withdraws all liquid T from the stake to the owner. Reverts if there is at least one non-zero authorization. Can be called only by the delegation owner or the staking provider. Can only be called when 24h passed since the stake has been delegated.

notifyKeepStakeDiscrepancy

function notifyKeepStakeDiscrepancy(address stakingProvider) external

Notifies about the discrepancy between legacy KEEP active stake and the amount cached in T staking contract. Slashes the staking provider in case the amount cached is higher than the actual active stake amount in KEEP staking contract. Needs to update authorizations of all affected applications and execute an involuntary authorization decrease on all affected applications. Can be called by anyone, notifier receives a reward.

notifyNuStakeDiscrepancy

function notifyNuStakeDiscrepancy(address stakingProvider) external

Notifies about the discrepancy between legacy NU active stake and the amount cached in T staking contract. Slashes the staking provider in case the amount cached is higher than the actual active stake amount in NU staking contract. Needs to update authorizations of all affected applications and execute an involuntary authorization decrease on all affected applications. Can be called by anyone, notifier receives a reward.

Real discrepancy between T and Nu is impossible. This method is a safeguard in case of bugs in NuCypher staking contract

setStakeDiscrepancyPenalty

function setStakeDiscrepancyPenalty(uint96 penalty, uint256 rewardMultiplier) external

Sets the penalty amount for stake discrepancy and reward multiplier for reporting it. The penalty is seized from the delegated stake, and 5% of the penalty, scaled by the multiplier, is given to the notifier. The rest of the tokens are burned. Can only be called by the Governance. See seize function.

setNotificationReward

function setNotificationReward(uint96 reward) external

Sets reward in T tokens for notification of misbehaviour of one staking provider. Can only be called by the governance.

pushNotificationReward

function pushNotificationReward(uint96 reward) external

Transfer some amount of T tokens as reward for notifications of misbehaviour

withdrawNotificationReward

function withdrawNotificationReward(address recipient, uint96 amount) external

Withdraw some amount of T tokens from notifiers treasury. Can only be called by the governance.

slash

function slash(uint96 amount, address[] _stakingProviders) external

Adds staking providers to the slashing queue along with the amount that should be slashed from each one of them. Can only be called by application authorized for all staking providers in the array.

This method doesn't emit events for providers that are added to the queue. If necessary events can be added to the application level.

seize

function seize(uint96 amount, uint256 rewardMultiplier, address notifier, address[] _stakingProviders) external

Adds staking providers to the slashing queue along with the amount. The notifier will receive reward per each provider from notifiers treasury. Can only be called by application authorized for all staking providers in the array.

This method doesn't emit events for staking providers that are added to the queue. If necessary events can be added to the application level.

processSlashing

function processSlashing(uint256 count) external virtual

Takes the given number of queued slashing operations and processes them. Receives 5% of the slashed amount. Executes involuntaryAuthorizationDecrease function on each affected application.

delegateVoting

function delegateVoting(address stakingProvider, address delegatee) external

Delegate voting power from the stake associated to the stakingProvider to a delegatee address. Caller must be the owner of this stake.

transferGovernance

function transferGovernance(address newGuvnor) external virtual

Transfers ownership of the contract to newGuvnor.

authorizedStake

function authorizedStake(address stakingProvider, address application) external view returns (uint96)

Returns the authorized stake amount of the staking provider for the application.

stakes

function stakes(address stakingProvider) external view returns (uint96 tStake, uint96 keepInTStake, uint96 nuInTStake)

Returns staked amount of T, Keep and Nu for the specified staking provider.

All values are in T denomination

getStartStakingTimestamp

function getStartStakingTimestamp(address stakingProvider) external view returns (uint256)

Returns start staking timestamp.

This value is set at most once.

stakedNu

function stakedNu(address stakingProvider) external view returns (uint256 nuAmount)

Returns staked amount of NU for the specified staking provider.

rolesOf

function rolesOf(address stakingProvider) external view returns (address owner, address payable beneficiary, address authorizer)

Gets the stake owner, the beneficiary and the authorizer for the specified staking provider address.

Return Values

NameTypeDescription

owner

address

Stake owner address.

beneficiary

address payable

Beneficiary address.

authorizer

address

Authorizer address.

getApplicationsLength

function getApplicationsLength() external view returns (uint256)

Returns length of application array

getSlashingQueueLength

function getSlashingQueueLength() external view returns (uint256)

Returns length of slashing queue

requestAuthorizationDecrease

function requestAuthorizationDecrease(address stakingProvider, address application, uint96 amount) public

Requests decrease of the authorization for the given staking provider on the given application by the provided amount. It may not change the authorized amount immediatelly. When it happens depends on the application. Can only be called by the given staking provider’s authorizer. Overwrites pending authorization decrease for the given staking provider and application if the application agrees for that. If the application does not agree for overwriting, the function reverts.

Calls authorizationDecreaseRequested callback on the given application. See IApplication.

getMinStaked

function getMinStaked(address stakingProvider, enum IStaking.StakeType stakeTypes) public view returns (uint96)

Returns minimum possible stake for T, KEEP or NU in T denomination

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 application authorization is 40 T, then getMinStaked for that staking provider returns:

  • 0 T if KEEP stake type specified i.e. min = 40 T max - (10 T + 30 T worth of NU) = 0 T

  • 10 T if NU stake type specified i.e. min = 40 T max - (10 T + 20 T worth of KEEP) = 10 T

  • 0 T if T stake type specified i.e. min = 40 T max - (20 T worth of KEEP + 30 T worth of NU) < 0 T In other words, the minimum stake amount for the specified stake type is the minimum amount of stake of the given type needed to satisfy the maximum application authorization given the staked amounts of the other stake types for that staking provider.

getAvailableToAuthorize

function getAvailableToAuthorize(address stakingProvider, address application) public view returns (uint96 availableTValue)

Returns available amount to authorize for the specified application.

delegate

function delegate(address stakingProvider, address delegatee) internal virtual

Delegate voting power from the stake associated to the stakingProvider to a delegatee address. Caller must be the owner of this stake.

Original abstract function defined in Checkpoints contract had two parameters, delegator and delegatee. Here we override it and comply with the same signature but the semantics of the first parameter changes to the stakingProvider address.

notify

function notify(uint96 amount, uint256 rewardMultiplier, address notifier, address[] _stakingProviders) internal

Adds staking providers to the slashing queue along with the amount. The notifier will receive reward per each staking provider from notifiers treasury. Can only be called by application authorized for all staking providers in the array.

processSlashing

function processSlashing(struct TokenStaking.SlashingEvent slashing) internal returns (uint96 tAmountToBurn)

Processes one specified slashing event. Executes involuntaryAuthorizationDecrease function on each affected application.

authorizationDecrease

function authorizationDecrease(address stakingProvider, struct TokenStaking.StakingProviderInfo stakingProviderStruct, uint96 slashedAmount) internal

Synchronize authorizations (if needed) after slashing stake

seizeKeep

function seizeKeep(struct TokenStaking.StakingProviderInfo stakingProviderStruct, address stakingProvider, uint96 tAmountToSlash, uint256 rewardMultiplier) internal returns (uint96)

Convert amount from T to Keep and call seize in Keep staking contract. Returns remainder of slashing amount in T

Note this internal function doesn't update stake checkpoints

seizeNu

function seizeNu(struct TokenStaking.StakingProviderInfo stakingProviderStruct, uint96 tAmountToSlash, uint256 rewardMultiplier) internal returns (uint96)

Convert amount from T to NU and call slashStaker in NuCypher staking contract. Returns remainder of slashing amount in T

Note this internal function doesn't update the stake checkpoints

cleanAuthorizedApplications

function cleanAuthorizedApplications(struct TokenStaking.StakingProviderInfo stakingProviderStruct, uint256 numberToDelete) internal

Removes application with zero authorization from authorized applications array

newStakeCheckpoint

function newStakeCheckpoint(address _delegator, uint96 _amount, bool increase) internal

Creates new checkpoints due to a change of stake amount

Parameters

NameTypeDescription

_delegator

address

Address of the staking provider acting as delegator

_amount

uint96

Amount of T to increment

increase

bool

True if the change is an increase, false if a decrease

increaseStakeCheckpoint

function increaseStakeCheckpoint(address _delegator, uint96 _amount) internal

Creates new checkpoints due to an increment of a stakers' stake

Parameters

NameTypeDescription

_delegator

address

Address of the staking provider acting as delegator

_amount

uint96

Amount of T to increment

decreaseStakeCheckpoint

function decreaseStakeCheckpoint(address _delegator, uint96 _amount) internal

Creates new checkpoints due to a decrease of a stakers' stake

Parameters

NameTypeDescription

_delegator

address

Address of the stake owner acting as delegator

_amount

uint96

Amount of T to decrease

getNuAmountInT

function getNuAmountInT(address owner, address stakingProvider) internal returns (uint96)

Returns amount of Nu stake in the NuCypher staking contract for the specified staking provider. Resulting value in T denomination

_transferGovernance

function _transferGovernance(address newGuvnor) internal virtual

getKeepAmountInT

function getKeepAmountInT(address stakingProvider) internal view returns (uint96)

Returns amount of Keep stake in the Keep staking contract for the specified staking provider. Resulting value in T denomination

convertToT

function convertToT(uint256 amount, uint256 ratio) internal pure returns (uint96 tAmount, uint256 remainder)

Returns the T token amount that's obtained from amount legacy tokens for the given ratio, and the remainder that can't be converted.

convertFromT

function convertFromT(uint96 tAmount, uint256 ratio) internal pure returns (uint256 amount, uint96 tRemainder)

Returns the amount of legacy tokens that's obtained from tAmount T tokens for the given ratio, and the T remainder that can't be converted.

Last updated