Skip to content

Latest commit

 

History

History
573 lines (477 loc) · 17.6 KB

StakingShared.md

File metadata and controls

573 lines (477 loc) · 17.6 KB

Staking modules shared functionality (StakingShared.sol)

View Source: contracts/governance/Staking/modules/shared/StakingShared.sol

↗ Extends: StakingStorageShared, SafeMath96 ↘ Derived Contracts: StakingAdminModule, StakingGovernanceModule, StakingStakeModule, StakingVestingModule, StakingWithdrawModule, WeightedStakingModule

StakingShared contract

Contract Members

Constants & Variables

uint256 internal constant FOUR_WEEKS;

Modifiers

whenNotPaused

Throws if paused.

modifier whenNotPaused() internal

onlyAuthorized

Throws if called by any account other than the owner or admin.

modifier onlyAuthorized() internal

onlyPauserOrOwner

Throws if called by any account other than the owner or pauser.

modifier onlyPauserOrOwner() internal

whenNotFrozen

Throws if frozen.

modifier whenNotFrozen() internal

Functions


constructor

function () internal nonpayable
Source Code
constructor() internal {
        // abstract
    }

_notSameBlockAsStakingCheckpoint

function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view

Arguments

Name Type Description
lockDate uint256
stakeFor address
Source Code
function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {
        uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];
        bool notSameBlock =
            userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;
        require(notSameBlock, "cannot be mined in the same block as last stake"); // S20
    }

_timestampToLockDate

Unstaking is possible every 2 weeks only. This means, to calculate the key value for the staking checkpoints, we need to map the intended timestamp to the closest available date.

function _timestampToLockDate(uint256 timestamp) internal view
returns(lockDate uint256)

Arguments

Name Type Description
timestamp uint256 The unlocking timestamp.

Returns

The actual unlocking date (might be up to 2 weeks shorter than intended).

Source Code
function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {
        // Optimize gas costs by reading kickoffTS from storage only once.
        uint256 start = kickoffTS;
        require(timestamp >= start, "timestamp < contract creation"); // WS23
        /**
         * @dev If staking timestamp does not match any of the unstaking dates
         * , set the lockDate to the closest one before the timestamp.
         * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.
         * */
        uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;
        lockDate = periodFromKickoff * TWO_WEEKS + start;
    }

_getCurrentBlockNumber

Determine the current Block Number

function _getCurrentBlockNumber() internal view
returns(uint256)
Source Code
function _getCurrentBlockNumber() internal view returns (uint256) {
        return block.number;
    }

_getPriorUserStakeByDate

Determine the prior number of stake for an account until a certain lock date as of a block number.

function _getPriorUserStakeByDate(address account, uint256 date, uint256 blockNumber) internal view
returns(uint96)

Arguments

Name Type Description
account address The address of the account to check.
date uint256 The lock date. Adjusted to the next valid lock date, if necessary.
blockNumber uint256 The block number to get the vote balance at.

Returns

The number of votes the account had as of the given block.

Source Code
function _getPriorUserStakeByDate(
        address account,
        uint256 date,
        uint256 blockNumber
    ) internal view returns (uint96) {
        require(blockNumber < _getCurrentBlockNumber(), "not determined"); // WS14

        date = _adjustDateForOrigin(date);
        uint32 nCheckpoints = numUserStakingCheckpoints[account][date];
        if (nCheckpoints == 0) {
            return 0;
        }

        /// @dev First check most recent balance.
        if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {
            return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;
        }

        /// @dev Next check implicit zero balance.
        if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {
            return 0;
        }

        uint32 lower = 0;
        uint32 upper = nCheckpoints - 1;
        while (upper > lower) {
            uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.
            Checkpoint memory cp = userStakingCheckpoints[account][date][center];
            if (cp.fromBlock == blockNumber) {
                return cp.stake;
            } else if (cp.fromBlock < blockNumber) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return userStakingCheckpoints[account][date][lower].stake;
    }

_adjustDateForOrigin

origin vesting contracts have different dates we need to add 2 weeks to get end of period (by default, it's start)

function _adjustDateForOrigin(uint256 date) internal view
returns(uint256)

Arguments

Name Type Description
date uint256 The staking date to compute the power for.

Returns

unlocking date.

Source Code
function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {
        uint256 adjustedDate = _timestampToLockDate(date);
        //origin vesting contracts have different dates
        //we need to add 2 weeks to get end of period (by default, it's start)
        if (adjustedDate != date) {
            date = adjustedDate + TWO_WEEKS;
        }
        return date;
    }

_computeWeightByDate

Compute the weight for a specific date.

function _computeWeightByDate(uint256 date, uint256 startDate) internal pure
returns(weight uint96)

Arguments

Name Type Description
date uint256 The unlocking date.
startDate uint256 We compute the weight for the tokens staked until 'date' on 'startDate'.

Returns

The weighted stake the account had as of the given block.

Source Code
function _computeWeightByDate(uint256 date, uint256 startDate)
        internal
        pure
        returns (uint96 weight)
    {
        require(date >= startDate, "date < startDate"); // WS18
        uint256 remainingTime = (date - startDate);
        require(MAX_DURATION >= remainingTime, "remaining time > max duration"); // WS19
        /// @dev x = max days - remaining days
        uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);
        /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)
        weight = add96(
            WEIGHT_FACTOR,
            mul96(
                MAX_VOTING_WEIGHT * WEIGHT_FACTOR,
                sub96(
                    MAX_DURATION_POW_2,
                    x * x,
                    "weight underflow" // WS20
                ),
                "weight mul overflow" // WS21
            ) / MAX_DURATION_POW_2,
            "overflow on weight" // WS22
        );
    }

_isVestingContract

Return flag whether the given address is a registered vesting contract.

function _isVestingContract(address stakerAddress) internal view
returns(bool)

Arguments

Name Type Description
stakerAddress address the address to check
Source Code
function _isVestingContract(address stakerAddress) internal view returns (bool) {
        bool isVesting;
        bytes32 codeHash;

        assembly {
            codeHash := extcodehash(stakerAddress)
        }
        if (address(vestingRegistryLogic) != address(0)) {
            isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);
        }

        if (isVesting) return true;
        if (vestingCodeHashes[codeHash]) return true;
        return false;
    }

Contracts