StakedToken

Git Source

Inherits: IStakedToken, ERC20Permit, IncreAccessControl, Pausable

Author: webthethird

Based on Aave's StakedToken, but with reward management outsourced to the SafetyModule

State Variables

_UNDERLYING_TOKEN

Address of the underlying token to stake

IERC20 internal immutable _UNDERLYING_TOKEN;

_COOLDOWN_SECONDS

Seconds that user must wait between calling cooldown and redeem

uint256 internal immutable _COOLDOWN_SECONDS;

_UNSTAKE_WINDOW

Seconds available to redeem once the cooldown period is fullfilled

uint256 internal immutable _UNSTAKE_WINDOW;

safetyModule

Address of the SafetyModule contract

ISafetyModule public safetyModule;

smRewardDistributor

Address of the SafetyModule's SMRewardDistributor contract

ISMRewardDistributor public smRewardDistributor;

isInPostSlashingState

Whether the StakedToken is in a post-slashing state

Post-slashing state disables staking and further slashing, and allows users to redeem their staked tokens without waiting for the cooldown period

bool public isInPostSlashingState;

maxStakeAmount

Max amount of staked tokens allowed per user

uint256 public maxStakeAmount;

exchangeRate

Exchange rate between the underlying token and the staked token, normalized to 1e18

Rate is the amount of underlying tokens held in this contract per staked token issued, so it should be 1e18 in normal conditions, when all staked tokens are backed 1:1 by underlying tokens, but it can be lower if users' stakes have been slashed for an auction by the SafetyModule

uint256 public exchangeRate;

_underlyingBalance

Internal accounting of total underlying token balance

uint256 internal _underlyingBalance;

_stakersCooldowns

Timestamp of the start of the current cooldown period for each user

mapping(address => uint256) internal _stakersCooldowns;

Functions

onlySafetyModule

Modifier for functions that can only be called by the SafetyModule contract

modifier onlySafetyModule();

constructor

StakedToken constructor

constructor(
    IERC20 _underlyingToken,
    ISafetyModule _safetyModule,
    uint256 _cooldownSeconds,
    uint256 _unstakeWindow,
    uint256 _maxStakeAmount,
    string memory _name,
    string memory _symbol
) payable ERC20(_name, _symbol) ERC20Permit(_name);

Parameters

getUnderlyingToken

Returns the underlying ERC20 token

function getUnderlyingToken() external view returns (IERC20);

Returns

getCooldownSeconds

Returns the length of the cooldown period

function getCooldownSeconds() external view returns (uint256);

Returns

getUnstakeWindowSeconds

Returns the length of the unstake window

function getUnstakeWindowSeconds() external view returns (uint256);

Returns

getCooldownStartTime

Returns the start time of the latest cooldown period for a given user

function getCooldownStartTime(address user) external view returns (uint256);

Parameters

Returns

previewStake

Returns the amount of staked tokens one would receive for staking an amount of underlying tokens

function previewStake(uint256 amountToStake) public view returns (uint256);

Parameters

Returns

previewRedeem

Returns the amount of underlying tokens one would receive for redeeming an amount of staked tokens

function previewRedeem(uint256 amountToRedeem) public view returns (uint256);

Parameters

Returns

stake

Stakes tokens from the sender and starts earning rewards

function stake(uint256 amount) external;

Parameters

stakeOnBehalfOf

Stakes tokens on behalf of the given address, and starts earning rewards

Tokens are transferred from the transaction sender, not from the onBehalfOf address

function stakeOnBehalfOf(address onBehalfOf, uint256 amount) external;

Parameters

redeem

Redeems staked tokens, and stop earning rewards

function redeem(uint256 amount) external;

Parameters

redeemTo

Redeems staked tokens, and stop earning rewards

Staked tokens are redeemed from the sender, and underlying tokens are sent to the to address

function redeemTo(address to, uint256 amount) external;

Parameters

cooldown

Activates the cooldown period to unstake

Can't be called if the user is not staking

function cooldown() external whenNotPaused;

getNextCooldownTimestamp

Calculates a new cooldown timestamp

Calculation depends on the sender/receiver situation, as follows:

  • If the timestamp of the sender is "better" or the timestamp of the recipient is 0, we take the one of the recipient

  • Weighted average of from/to cooldown timestamps if:

    • The sender doesn't have the cooldown activated (timestamp 0).

    • The sender timestamp is expired

    • The sender has a "worse" timestamp

  • If the receiver's cooldown timestamp expired (too old), the next is 0*

function getNextCooldownTimestamp(
    uint256 fromCooldownTimestamp,
    uint256 amountToReceive,
    address toAddress,
    uint256 toBalance
) public view returns (uint256);

Parameters

Returns

paused

Indicates whether staking and transferring are currently paused

Contract is paused if either this contract or the SafetyModule has been paused

function paused() public view override returns (bool);

Returns

slash

Sends underlying tokens to the given address, lowers the exchange rate accordingly, and changes the contract's state to POST_SLASHING, which disables staking, cooldown period and further slashing until the state is returned to RUNNING

function slash(address destination, uint256 amount) external onlySafetyModule returns (uint256);

Parameters

Returns

returnFunds

Transfers underlying tokens from the given address to this contract and increases the exchange rate accordingly

Only callable by the SafetyModule contract

function returnFunds(address from, uint256 amount) external onlySafetyModule;

Parameters

settleSlashing

Sets isInPostSlashingState to false, which re-enables staking, slashing and cooldown period

Only callable by the SafetyModule contract

function settleSlashing() external onlySafetyModule;

setRewardDistributor

Updates the stored SMRewardDistributor contract

Only callable by the SafetyModule contract in SafetyModule.setRewardDistributor

function setRewardDistributor(ISMRewardDistributor _newRewardDistributor) external onlySafetyModule;

Parameters

setSafetyModule

Changes the SafetyModule contract used for reward management

Only callable by governance

function setSafetyModule(address _newSafetyModule) external onlyRole(GOVERNANCE);

Parameters

setMaxStakeAmount

Sets the max amount of staked tokens allowed per user

Only callable by governance

function setMaxStakeAmount(uint256 _newMaxStakeAmount) external onlyRole(GOVERNANCE);

Parameters

pause

Pauses staking and transferring of staked tokens

Only callable by governance

function pause() external onlyRole(GOVERNANCE);

unpause

Unpauses staking and transferring of staked tokens

Only callable by governance

function unpause() external onlyRole(GOVERNANCE);

_updateExchangeRate

Updates the exchange rate of the staked token,

Based on this contract's current underlying token balance and the total supply of the staked token

function _updateExchangeRate(uint256 totalAssets, uint256 totalShares) internal;

_transfer

Internal ERC20 _transfer of the tokenized staked tokens

Updates the cooldown timestamps if necessary, and updates the staking positions of both users in the SafetyModule, accruing rewards in the process

function _transfer(address from, address to, uint256 amount) internal override whenNotPaused;

Parameters

_stake

Internal staking function, accrues rewards after updating user's position

Transfers underlying tokens from the from address and mints staked tokens to the to address

Reverts if any of the following conditions are met:

  • The contract is paused

  • The amount to stake is zero

  • The current exchange rate is zero (i.e., all underlying tokens have been slashed)

  • The contract is in a post-slashing state

  • The user's stake balance would exceed the max stake amount

  • The user's underlying token balance is insufficient

  • The user has not approved this contract to transfer the amount of underlying tokens

function _stake(address from, address to, uint256 amount) internal whenNotPaused;

Parameters

_redeem

Internal redeeming function, accrues rewards after updating user's position

Burns staked tokens from the from address and transfers underlying tokens to the to address

Reverts if any of the following conditions are met:

  • The user's staked token balance is zero

  • The amount to redeem is zero

  • The current exchange rate is zero (i.e., all underlying tokens have been slashed)

  • The user's cooldown period is not over

  • The unstake window has passed*

function _redeem(address from, address to, uint256 amount) internal;

Parameters

Last updated