View Source: contracts/governance/Staking/modules/StakingWithdrawModule.sol
↗ Extends: IFunctionsList, StakingShared, CheckpointsShared
struct VestingConfig {
address vestingAddress,
uint256 startDate,
uint256 endDate,
uint256 cliff,
uint256 duration,
address tokenOwner
}
Events
event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);
event StakingWithdrawn(address indexed staker, uint256 amount, uint256 until, address indexed receiver, bool isGovernance);
event VestingTokensWithdrawn(address vesting, address receiver);
event TokensUnlocked(uint256 amount);
- withdraw(uint96 amount, uint256 until, address receiver)
- cancelTeamVesting(address vesting, address receiver, uint256 startFrom)
- _cancelTeamVesting(address _vesting, address _receiver, uint256 _startFrom)
- _withdraw(uint96 amount, uint256 until, address receiver, bool isGovernance)
- _withdrawFromTeamVesting(uint96 amount, uint256 until, address receiver, struct StakingWithdrawModule.VestingConfig vestingConfig)
- _withdrawNext(uint256 until, address receiver, bool isGovernance)
- getWithdrawAmounts(uint96 amount, uint256 until)
- _getPunishedAmount(uint96 amount, uint256 until)
- _validateWithdrawParams(address account, uint96 amount, uint256 until)
- unlockAllTokens()
- setMaxVestingWithdrawIterations(uint256 newMaxIterations)
- governanceWithdrawVesting(address vesting, address receiver)
- governanceWithdraw(uint96 amount, uint256 until, address receiver)
- getFunctionsList()
Withdraw the given amount of tokens if they are unlocked.
function withdraw(uint96 amount, uint256 until, address receiver) external nonpayable whenNotFrozen
Arguments
Name | Type | Description |
---|---|---|
amount | uint96 | The number of tokens to withdraw. |
until | uint256 | The date until which the tokens were staked. |
receiver | address | The receiver of the tokens. If not specified, send to the msg.sender |
Source Code
function withdraw(
uint96 amount,
uint256 until,
address receiver
) external whenNotFrozen {
// adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to
// _notSameBlockAsStakingCheckpoint
until = _adjustDateForOrigin(until);
_notSameBlockAsStakingCheckpoint(until, msg.sender);
_withdraw(amount, until, receiver, false);
// @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract
// we need to check block.timestamp here
_withdrawNext(until, receiver, false);
}
Governance withdraw vesting directly through staking contract. This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing. This function only allows cancelling vesting contract of the TeamVesting type. *
function cancelTeamVesting(address vesting, address receiver, uint256 startFrom) external nonpayable onlyAuthorized whenNotFrozen
Arguments
Name | Type | Description |
---|---|---|
vesting | address | The vesting address. |
receiver | address | The receiving address. |
startFrom | uint256 | The start value for the iterations. |
Source Code
function cancelTeamVesting(
address vesting,
address receiver,
uint256 startFrom
) external onlyAuthorized whenNotFrozen {
/// require the caller only for team vesting contract.
require(vestingRegistryLogic.isTeamVesting(vesting), "Only team vesting allowed");
_cancelTeamVesting(vesting, receiver, startFrom);
}
Withdraws tokens from the staking contract and forwards them to an address specified by the token owner. Low level function.
function _cancelTeamVesting(address _vesting, address _receiver, uint256 _startFrom) private nonpayable
Arguments
Name | Type | Description |
---|---|---|
_vesting | address | The vesting address. |
_receiver | address | The receiving address. |
_startFrom | uint256 | The start value for the iterations. or just unlocked tokens (false). |
Source Code
function _cancelTeamVesting(
address _vesting,
address _receiver,
uint256 _startFrom
) private {
require(_receiver != address(0), "receiver address invalid");
ITeamVesting teamVesting = ITeamVesting(_vesting);
VestingConfig memory vestingConfig =
VestingConfig(
_vesting,
teamVesting.startDate(),
teamVesting.endDate(),
teamVesting.cliff(),
teamVesting.duration(),
teamVesting.tokenOwner()
);
/// @dev In the unlikely case that all tokens have been unlocked early,
/// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.
uint256 end = vestingConfig.endDate;
uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;
_startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;
/// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1
uint256 totalIterationValue =
(_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));
uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;
/// @dev Withdraw for each unlocked position.
for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {
/// @dev Read amount to withdraw.
uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);
if (tempStake > 0) {
/// @dev do governance direct withdraw for team vesting
_withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);
}
}
if (adjustedEnd < end) {
emit TeamVestingPartiallyCancelled(msg.sender, _receiver, adjustedEnd);
} else {
emit TeamVestingCancelled(msg.sender, _receiver);
}
}
Send user' staked tokens to a receiver taking into account punishments. Sovryn encourages long-term commitment and thinking. When/if you unstake before the end of the staking period, a percentage of the original staking amount will be slashed. This amount is also added to the reward pool and is distributed between all other stakers. *
function _withdraw(uint96 amount, uint256 until, address receiver, bool isGovernance) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
amount | uint96 | The number of tokens to withdraw. |
until | uint256 | The date until which the tokens were staked. Needs to be adjusted to the next valid lock date before calling this function. |
receiver | address | The receiver of the tokens. If not specified, send to the msg.sender |
isGovernance | bool | Whether all tokens (true) or just unlocked tokens (false). |
Source Code
function _withdraw(
uint96 amount,
uint256 until,
address receiver,
bool isGovernance
) internal {
// @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract
// this check is a part of workaround for Vesting.withdrawTokens issue
if (amount == 1 && _isVestingContract(msg.sender)) {
return;
}
_validateWithdrawParams(msg.sender, amount, until);
/// @dev Determine the receiver.
if (receiver == address(0)) receiver = msg.sender;
/// @dev Update the checkpoints.
_decreaseDailyStake(until, amount);
_decreaseUserStake(msg.sender, until, amount);
if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);
_decreaseDelegateStake(delegates[msg.sender][until], until, amount);
/// @dev Early unstaking should be punished.
if (block.timestamp < until && !allUnlocked && !isGovernance) {
uint96 punishedAmount = _getPunishedAmount(amount, until);
amount -= punishedAmount;
/// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'
if (punishedAmount > 0) {
require(address(feeSharing) != address(0), "FeeSharing address wasn't set"); // S08
/// @dev Move punished amount to fee sharing.
/// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.
SOVToken.approve(address(feeSharing), punishedAmount);
feeSharing.transferTokens(address(SOVToken), punishedAmount);
}
}
/// @dev transferFrom
bool success = SOVToken.transfer(receiver, amount);
require(success, "Token transfer failed"); // S09
emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);
}
Send user' staked tokens to a receiver. This function is dedicated only for direct withdrawal from staking contract. Currently only being used by cancelTeamVesting() *
function _withdrawFromTeamVesting(uint96 amount, uint256 until, address receiver, struct StakingWithdrawModule.VestingConfig vestingConfig) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
amount | uint96 | The number of tokens to withdraw. |
until | uint256 | The date until which the tokens were staked. |
receiver | address | The receiver of the tokens. If not specified, send to the msg.sender. |
vestingConfig | struct StakingWithdrawModule.VestingConfig | The vesting config. |
Source Code
function _withdrawFromTeamVesting(
uint96 amount,
uint256 until,
address receiver,
VestingConfig memory vestingConfig
) internal {
address vesting = vestingConfig.vestingAddress;
until = _timestampToLockDate(until);
_validateWithdrawParams(vesting, amount, until);
/// @dev Update the checkpoints.
_decreaseDailyStake(until, amount);
_decreaseUserStake(vesting, until, amount);
_decreaseVestingStake(until, amount);
_decreaseDelegateStake(delegates[vesting][until], until, amount);
/// @dev transferFrom
bool success = SOVToken.transfer(receiver, amount);
require(success, "Token transfer failed"); // S09
emit StakingWithdrawn(vesting, amount, until, receiver, true);
}
function _withdrawNext(uint256 until, address receiver, bool isGovernance) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
until | uint256 | |
receiver | address | |
isGovernance | bool |
Source Code
function _withdrawNext(
uint256 until,
address receiver,
bool isGovernance
) internal {
if (_isVestingContract(msg.sender)) {
// nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally
// withdraw stakes that are in the future and would get slashed (if until is not
// a valid lock date). but until is already handled in the withdraw function
uint256 nextLock = until.add(TWO_WEEKS);
if (isGovernance || block.timestamp >= nextLock) {
uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);
if (stakes > 0) {
_withdraw(stakes, nextLock, receiver, isGovernance);
}
}
}
}
Get available and punished amount for withdrawing.
function getWithdrawAmounts(uint96 amount, uint256 until) external view
returns(uint96, uint96)
Arguments
Name | Type | Description |
---|---|---|
amount | uint96 | The number of tokens to withdraw. |
until | uint256 | The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary. |
Source Code
function getWithdrawAmounts(uint96 amount, uint256 until)
external
view
returns (uint96, uint96)
{
until = _adjustDateForOrigin(until);
_validateWithdrawParams(msg.sender, amount, until);
uint96 punishedAmount = _getPunishedAmount(amount, until);
return (amount - punishedAmount, punishedAmount);
}
Get punished amount for withdrawing.
function _getPunishedAmount(uint96 amount, uint256 until) internal view
returns(uint96)
Arguments
Name | Type | Description |
---|---|---|
amount | uint96 | The number of tokens to withdraw. |
until | uint256 | The date until which the tokens were staked. |
Source Code
function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {
uint256 date = _timestampToLockDate(block.timestamp);
uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR
weight = weight * weightScaling;
return (amount * weight) / WEIGHT_FACTOR / 100;
}
Validate withdraw parameters.
function _validateWithdrawParams(address account, uint96 amount, uint256 until) internal view
Arguments
Name | Type | Description |
---|---|---|
account | address | Address to be validated. |
amount | uint96 | The number of tokens to withdraw. |
until | uint256 | The date until which the tokens were staked. |
Source Code
function _validateWithdrawParams(
address account,
uint96 amount,
uint256 until
) internal view {
require(amount > 0, "Amount of tokens to withdraw must be > 0"); // S10
uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);
require(amount <= balance, "Staking::withdraw: not enough balance"); // S11
}
Allow the owner to unlock all tokens in case the staking contract is going to be replaced Note: Not reversible on purpose. once unlocked, everything is unlocked. The owner should not be able to just quickly unlock to withdraw his own tokens and lock again.
function unlockAllTokens() external nonpayable onlyOwner whenNotFrozen
Source Code
function unlockAllTokens() external onlyOwner whenNotFrozen {
allUnlocked = true;
emit TokensUnlocked(SOVToken.balanceOf(address(this)));
}
set max withdraw iterations. *
function setMaxVestingWithdrawIterations(uint256 newMaxIterations) external nonpayable onlyAuthorized whenNotFrozen
Arguments
Name | Type | Description |
---|---|---|
newMaxIterations | uint256 | new max iterations value. |
Source Code
function setMaxVestingWithdrawIterations(uint256 newMaxIterations)
external
onlyAuthorized
whenNotFrozen
{
require(newMaxIterations > 0, "Invalid max iterations");
emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);
maxVestingWithdrawIterations = newMaxIterations;
}
Withdraw tokens for vesting contract.
function governanceWithdrawVesting(address vesting, address receiver) public nonpayable onlyAuthorized whenNotFrozen
Arguments
Name | Type | Description |
---|---|---|
vesting | address | The address of Vesting contract. |
receiver | address | The receiver of the tokens. If not specified, send to the msg.sender |
Source Code
function governanceWithdrawVesting(address vesting, address receiver)
public
onlyAuthorized
whenNotFrozen
{
vestingWhitelist[vesting] = true;
ITeamVesting(vesting).governanceWithdrawTokens(receiver);
vestingWhitelist[vesting] = false;
emit VestingTokensWithdrawn(vesting, receiver);
}
Withdraw the given amount of tokens.
function governanceWithdraw(uint96 amount, uint256 until, address receiver) external nonpayable whenNotFrozen
Arguments
Name | Type | Description |
---|---|---|
amount | uint96 | The number of tokens to withdraw. |
until | uint256 | The date until which the tokens were staked. |
receiver | address | The receiver of the tokens. If not specified, send to the msg.sender |
Source Code
function governanceWithdraw(
uint96 amount,
uint256 until,
address receiver
) external whenNotFrozen {
require(vestingWhitelist[msg.sender], "unauthorized"); // S07
_notSameBlockAsStakingCheckpoint(until, msg.sender);
_withdraw(amount, until, receiver, true);
// @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract
// we don't need to check block.timestamp here
_withdrawNext(until, receiver, true);
}
undefined
function getFunctionsList() external pure
returns(bytes4[])
Source Code
function getFunctionsList() external pure returns (bytes4[] memory) {
bytes4[] memory functionsList = new bytes4[](7);
functionsList[0] = this.withdraw.selector;
functionsList[1] = this.cancelTeamVesting.selector;
functionsList[2] = this.getWithdrawAmounts.selector;
functionsList[3] = this.unlockAllTokens.selector;
functionsList[4] = this.setMaxVestingWithdrawIterations.selector;
functionsList[5] = this.governanceWithdraw.selector;
functionsList[6] = this.governanceWithdrawVesting.selector;
return functionsList;
}
- Address
- Administered
- AdminRole
- AdvancedToken
- AdvancedTokenStorage
- Affiliates
- AffiliatesEvents
- ApprovalReceiver
- BProPriceFeed
- CheckpointsShared
- Constants
- Context
- DevelopmentFund
- DummyContract
- EnumerableAddressSet
- EnumerableBytes32Set
- EnumerableBytes4Set
- ERC20
- ERC20Detailed
- ErrorDecoder
- Escrow
- EscrowReward
- FeedsLike
- FeesEvents
- FeeSharingCollector
- FeeSharingCollectorProxy
- FeeSharingCollectorStorage
- FeesHelper
- FourYearVesting
- FourYearVestingFactory
- FourYearVestingLogic
- FourYearVestingStorage
- GenericTokenSender
- GovernorAlpha
- GovernorVault
- IApproveAndCall
- IChai
- IContractRegistry
- IConverterAMM
- IERC1820Registry
- IERC20_
- IERC20
- IERC777
- IERC777Recipient
- IERC777Sender
- IFeeSharingCollector
- IFourYearVesting
- IFourYearVestingFactory
- IFunctionsList
- ILiquidityMining
- ILiquidityPoolV1Converter
- ILoanPool
- ILoanToken
- ILoanTokenLogicBeacon
- ILoanTokenLogicModules
- ILoanTokenLogicProxy
- ILoanTokenModules
- ILoanTokenWRBTC
- ILockedSOV
- IMoCState
- IModulesProxyRegistry
- Initializable
- InterestUser
- IPot
- IPriceFeeds
- IPriceFeedsExt
- IProtocol
- IRSKOracle
- ISovryn
- ISovrynSwapNetwork
- IStaking
- ISwapsImpl
- ITeamVesting
- ITimelock
- IV1PoolOracle
- IVesting
- IVestingFactory
- IVestingRegistry
- IWrbtc
- IWrbtcERC20
- LenderInterestStruct
- LiquidationHelper
- LiquidityMining
- LiquidityMiningConfigToken
- LiquidityMiningProxy
- LiquidityMiningStorage
- LoanClosingsEvents
- LoanClosingsLiquidation
- LoanClosingsRollover
- LoanClosingsShared
- LoanClosingsWith
- LoanClosingsWithoutInvariantCheck
- LoanInterestStruct
- LoanMaintenance
- LoanMaintenanceEvents
- LoanOpenings
- LoanOpeningsEvents
- LoanParamsStruct
- LoanSettings
- LoanSettingsEvents
- LoanStruct
- LoanToken
- LoanTokenBase
- LoanTokenLogicBeacon
- LoanTokenLogicLM
- LoanTokenLogicProxy
- LoanTokenLogicStandard
- LoanTokenLogicStorage
- LoanTokenLogicWrbtc
- LoanTokenSettingsLowerAdmin
- LockedSOV
- MarginTradeStructHelpers
- Medianizer
- ModuleCommonFunctionalities
- ModulesCommonEvents
- ModulesProxy
- ModulesProxyRegistry
- MultiSigKeyHolders
- MultiSigWallet
- Mutex
- Objects
- OrderStruct
- OrigingVestingCreator
- OriginInvestorsClaim
- Ownable
- Pausable
- PausableOz
- PreviousLoanToken
- PreviousLoanTokenSettingsLowerAdmin
- PriceFeedRSKOracle
- PriceFeeds
- PriceFeedsLocal
- PriceFeedsMoC
- PriceFeedV1PoolOracle
- ProtocolAffiliatesInterface
- ProtocolLike
- ProtocolSettings
- ProtocolSettingsEvents
- ProtocolSettingsLike
- ProtocolSwapExternalInterface
- ProtocolTokenUser
- Proxy
- ProxyOwnable
- ReentrancyGuard
- RewardHelper
- RSKAddrValidator
- SafeERC20
- SafeMath
- SafeMath96
- setGet
- SharedReentrancyGuard
- SignedSafeMath
- SOV
- sovrynProtocol
- StakingAdminModule
- StakingGovernanceModule
- StakingInterface
- StakingProxy
- StakingRewards
- StakingRewardsProxy
- StakingRewardsStorage
- StakingShared
- StakingStakeModule
- StakingStorageModule
- StakingStorageShared
- StakingVestingModule
- StakingWithdrawModule
- State
- SwapsEvents
- SwapsExternal
- SwapsImplLocal
- SwapsImplSovrynSwap
- SwapsUser
- TeamVesting
- Timelock
- TimelockHarness
- TimelockInterface
- TokenSender
- UpgradableProxy
- USDTPriceFeed
- Utils
- VaultController
- Vesting
- VestingCreator
- VestingFactory
- VestingLogic
- VestingRegistry
- VestingRegistry2
- VestingRegistry3
- VestingRegistryLogic
- VestingRegistryProxy
- VestingRegistryStorage
- VestingStorage
- WeightedStakingModule
- WRBTC