Staking

Allowlisted underlying token(s) can be staked in the safety module to help protect the protocol from a short fall event and earn rewards in return. There are 4 possible actions as a staker, aside from those typical of ERC-20 tokens:

  1. Stake

  2. Redeem

  3. Start cooldown

  4. Claim rewards

For an underlying token to be allowlisted for staking, a staking contract must be deployed for it. Our StakedToken contract is adapted from Aave's, with the primary difference that we outsourced reward management to a separate module in the greater safety module. The cooldown system is largely unchanged, and slashing very similar.

In the unlikely situation of a short fall event, governance can initiate an auction to sell off a necessary portion of the staked funds. There are 2 possible actions as an auction participant:

  1. Buy lot(s)

  2. Complete an expired auction

The use of the auction mechanism is seldom because the potential deficits created by [risk factors](../risk-factors.md) will be first covered by funds in the [Insurance](../core-contracts/Insurance.md). In a rare case where there is a substantial shortfall in the protocol then the auction mechanism is used as the second line of defence for the protocol and its participants.

Stake

Anyone who owns an allowlisted staking token can stake their tokens on Increment by calling the stake function in the StakedToken contract. The sequence of actions for staking is as follows:

  1. The system first checks whether it is in a post slashing state (ie. the state after an auction has been initiated). If it is, then staking is not allowed and the transaction reverts with an error message, otherwise the check passes.

  2. The shares to mint for the staked tokens is computed from the underlying staked amount and the exchange rate.

  3. The system then checks whether the staked amount is greater than the max cap. If it is greater then the transaction reverts, otherwise the check passes.

  4. The user's cooldown timestamp is updated if they are currently in a cooldown period.

  5. Mint staked tokens and transfer in underlying staked amount.

  6. The system updates user's staking position and rewards in the SafetyModule

Redeem

Users can withdraw their underlying tokens by calling the redeem function in the StakedToken contract. Note that, unless the system is in a post slashing state, users must first start their cooldown period and wait for it to pass, after which they will have another time window in which to redeem their tokens.

The sequence of actions for redeeming the staked amount is as follows:

  1. The system first checks whether it is in a post slashing state. If it is, then redeeming is allowed at any time. If it is not, the system then checks whether the cooldown period is over for the user, if the cooldown period is not over, the transaction reverts otherwise the system proceeds to the next check. The next check is the unstake window, if the unstake window has passed then the transaction reverts otherwise the check passes.

The cooldown period is the waiting time required prior to unstaking your tokens. You must start the cooldown period before you can unstake your tokens.

Please note that after the cooldown period is complete, you will have a time window where you can unstake. If you do not unstake during that period, you will have to start the cooldown process over again.

  1. The amount of underlying tokens to redeem is computed from the staked amount and the exchange rate.

  2. The user's cooldown timestamp is updated and if the remaining balance is zero then the cooldown timestamp is reset.

  3. Burn staked tokens and transfer out underlying staked amount.

  4. The system updates user's staking position and rewards in the SafetyModule

Start cooldown

Users must start the cooldown period by calling the cooldown function in the StakedToken contract, and then wait the duration of the period, before they can redeem their tokens. To discourage bad actors from potentially gaming the system by repeatedly entering the cooldown period without redeeming, entering cooldown also resets the user's reward multiplier to 1, though only after accruing any rewards they are due at their current multiplier. Rewards still accrue during the cooldown period and the subsequent unstake window.

After the cooldown period is over, the user has a time window in which to redeem their tokens. If they do not redeem their tokens during this time window, they will have to start the cooldown period over again.

Claim rewards

Depending on the amount of reward tokens in the EcosystemReserve on Ethereum mainnet, stakers are eligible to earn rewards for providing economic security to the protocol. The system can support more than one reward token.

The speed of reward accrual for stakers is dependent on the reward distribution parameters set by governance and a multiplier score that is calculated for each user. The multiplier increases the user's reward and is calculated based on the following formula:

multiplier=maxRewardMultiplier1deltaDayssmoothingValue+1maxRewardMultiplier1{multiplier}={maxRewardMultiplier} - \frac{1}{\frac{deltaDays}{smoothingValue} + \frac{1}{maxRewardMultiplier - 1}}

The multiplier will be relatively greater for those who have staked for a longer duration without changing their position.

Users can redeem staked tokens by calling the redeem function in the StakedToken contract. The sequence of actions for claiming staking rewards is as follows:

  1. For each market (the system considers StakedToken contracts to be "markets", and still need to loop over them since each has its own reward accumulator), the system checks whether the current staking position is registered for rewards. If not, the transaction reverts.

  2. For each reward token, update the reward accumulator for this market. Then compute the user's reward multiplier based on their staking duration and stake position. Add the rewards accrued by the user.

  3. Check whether the Ecosystem Reserve has enough reward tokens. If so, then transfer all the user's rewards. If not, transfer any remaining reward tokens to user.

  4. Subtract transferred amount from user's accrued rewards.

Auctions

The auction module handles auctioning tokens slashed by the SafetyModule. In the event of an insolvency in the Vault which cannot be covered by the Insurance contract, the auction module can be triggered via governance by calling the slashAndStartAuction function in the SafetyModule contract.

The auction mechanism is similar to a Dutch auction, but with the key difference that the price of a lot is fixed while the number of tokens in each lot increases over time, such that the price paid per token decreases over time. The auction ends when all lots are sold, when the auction time limit is reached, or if governance terminates it early. In the case where the auction's time limit expires, no more lots can be sold, but it is necessary for someone to call completeAuction before the funds raised and unsold tokens can be transferred.

The following parameters are initialized via governance at the start of a new auction:

Name
Type
Description

_token

IERC20

The ERC20 token to auction

_numLots

uint8

Number of lots in the auction

_lotPrice

uint128

Price of each lot of tokens in payment tokens

_initialLotSize

uint128

Initial number of tokens in each lot

_slashPercent

uint64

Percentage of staked tokens to slash

_lotIncreaseIncrement

uint96

Amount of tokens by which the lot size increases each period

_lotIncreasePeriod

uint16

Number of seconds between each lot size increase

_timeLimit

uint32

Number of seconds before the auction ends if all lots are not sold

Buying lots

Anyone can buy one or more lots by calling the buyLots(auctionId, numLots) function in the AuctionModule contract. The price per lot, which is fixed, can be retrieved by calling the getLotPrice(auctionId) function. To get the current lot size, which increases over time, call the getCurrentLotSize(auctionId) function. Similarly, to view the number of lots remaining, call the getRemainingLots(auctionId) function.

The sequence of actions for buying tokens from an auction is as follows:

  1. The buyer checks whether the auction ID and the number of lots to buy is valid. If not, the transaction will revert.

  2. The buyer computes their payment amount by multiplying the number of lots they wish to buy and the lot price. They will also compute the current lot size to determine whether they like their bid.

  3. The system checks whether the lot size multiplied by remaining number of lots is greater than the auctionable balance. If it is, the system will cap the lot size at auctionable balance divided by remaining number of lots.

  4. If the buyer proceeds with the purchase, the system will subtract the number of lots that the buyer purchased from the remaining lots, add the purchased token amount to the total tokens sold per auction, and add the payment amount to the total funds raised per auction.

  5. The system checks whether the buyer has approved the payment transfer. If not, the transaction will revert.

  6. The system checks whether the buyer has enough payment token. If not, the transaction will revert.

  7. Transfer payment tokens from buyer to auction module and transfer purchased tokens to buyer.

  8. If the auction is sold out after this transaction, the system will complete the auction, starting from step 4 in the Completing an expired auction section.

Completing an expired auction

Calling completeAuction(auctionId) directly on the auction module is only necessary if the auction's time limit has expired before selling out all lots, and is only possible if the auction has not already been completed.

The sequence of actions for completing an expired auction is as follows:

  1. The system checks whether the auction ID is valid. If not, the transaction will revert.

  2. The system checks whether the auction has already been completed. If so, the transaction will revert.

  3. The system checks whether the auction has expired. If not, the transaction will revert.

  4. The system updates the active flag to false for the auction.

  5. If the auction module has any remaining unsold tokens, it will approve the appropriate amount of tokens to be transferred by the StakedToken contract to itself.

  6. If the auction raised any funds, it will approve the appropriate amount of tokens to be transferred by the SafetyModule contract to governance.

  7. The system tells the SafetyModule that the auction has ended.

  8. If there were any unsold tokens, the SafetyModule calls returnFunds on the StakedToken contract to transfer the unsold tokens to itself and raise its exchange rate.

  9. The SafetyModule calls settleSlashing on the StakedToken contract to end the post-slashing state, reenabling staking, slashing and cooldown.

Last updated