- (VestingRegistry.sol)
View Source: contracts/governance/Vesting/VestingRegistry.sol
↗ Extends: Ownable
On January 25, 2020, Sovryn launched the Genesis Reservation system. Sovryn community members who controlled a special NFT were granted access to stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event, which will be redeemable on a 1:1 basis for cSOV, subject to approval by existing SOV holders.
- On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized financial sovereignty with the vote on SIP 0005. This proposal will enable participants of the Genesis Reservation system to redeem their reserved cSOV tokens for SOV. They will also have the choice to redeem cSOV for rBTC if they decide to exit the system.
- This contract deals with the vesting and redemption of cSOV tokens.
Enums
enum VestingType {
TeamVesting,
Vesting
}
Constants & Variables
uint256 public constant FOUR_WEEKS;
uint256 public constant CSOV_VESTING_CLIFF;
uint256 public constant CSOV_VESTING_DURATION;
contract IVestingFactory public vestingFactory;
address public SOV;
address[] public CSOVtokens;
uint256 public priceSats;
address public staking;
address public feeSharingCollector;
address public vestingOwner;
mapping(address => mapping(uint256 => address)) public vestingContracts;
mapping(address => bool) public processedList;
mapping(address => bool) public blacklist;
mapping(address => uint256) public lockedAmount;
mapping(address => bool) public admins;
Events
event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);
event CSOVTokensExchanged(address indexed caller, uint256 amount);
event SOVTransferred(address indexed receiver, uint256 amount);
event VestingCreated(address indexed tokenOwner, address vesting, uint256 cliff, uint256 duration, uint256 amount);
event TeamVestingCreated(address indexed tokenOwner, address vesting, uint256 cliff, uint256 duration, uint256 amount);
event TokensStaked(address indexed vesting, uint256 amount);
event AdminAdded(address admin);
event AdminRemoved(address admin);
Throws if called by any account other than the owner or admin. TODO: This ACL logic should be available on OpenZeppeling Ownable.sol or on our own overriding sovrynOwnable. This same logic is repeated on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol
modifier onlyAuthorized() internal
modifier isNotProcessed() internal
modifier isNotBlacklisted() internal
- constructor(address _vestingFactory, address _SOV, address[] _CSOVtokens, uint256 _priceSats, address _staking, address _feeSharingCollector, address _vestingOwner)
- addAdmin(address _admin)
- removeAdmin(address _admin)
- reImburse()
- budget()
- deposit()
- withdrawAll(address payable to)
- setVestingFactory(address _vestingFactory)
- _setVestingFactory(address _vestingFactory)
- setCSOVtokens(address[] _CSOVtokens)
- _setCSOVtokens(address[] _CSOVtokens)
- setBlacklistFlag(address _account, bool _blacklisted)
- setLockedAmount(address _account, uint256 _amount)
- transferSOV(address _receiver, uint256 _amount)
- exchangeAllCSOV()
- _createVestingForCSOV(uint256 _amount)
- _validateCSOV(address _CSOV)
- createVesting(address _tokenOwner, uint256 _amount, uint256 _cliff, uint256 _duration)
- createTeamVesting(address _tokenOwner, uint256 _amount, uint256 _cliff, uint256 _duration)
- stakeTokens(address _vesting, uint256 _amount)
- getVesting(address _tokenOwner)
- getTeamVesting(address _tokenOwner)
- _getOrCreateVesting(address _tokenOwner, uint256 _cliff, uint256 _duration)
- _getOrCreateTeamVesting(address _tokenOwner, uint256 _cliff, uint256 _duration)
Contract deployment settings.
function (address _vestingFactory, address _SOV, address[] _CSOVtokens, uint256 _priceSats, address _staking, address _feeSharingCollector, address _vestingOwner) public nonpayable
Arguments
Name | Type | Description |
---|---|---|
_vestingFactory | address | The address of vesting factory contract. |
_SOV | address | The SOV token address. |
_CSOVtokens | address[] | The array of cSOV tokens. |
_priceSats | uint256 | The price of cSOV tokens in satoshis. |
_staking | address | The address of staking contract. |
_feeSharingCollector | address | The address of fee sharing collector proxy contract. |
_vestingOwner | address | The address of an owner of vesting contract. |
Source Code
constructor(
address _vestingFactory,
address _SOV,
address[] memory _CSOVtokens,
uint256 _priceSats,
address _staking,
address _feeSharingCollector,
address _vestingOwner
) public {
require(_SOV != address(0), "SOV address invalid");
require(_staking != address(0), "staking address invalid");
require(_feeSharingCollector != address(0), "feeSharingCollector address invalid");
require(_vestingOwner != address(0), "vestingOwner address invalid");
_setVestingFactory(_vestingFactory);
_setCSOVtokens(_CSOVtokens);
SOV = _SOV;
priceSats = _priceSats;
staking = _staking;
feeSharingCollector = _feeSharingCollector;
vestingOwner = _vestingOwner;
}
Add account to ACL.
function addAdmin(address _admin) public nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
_admin | address | The addresses of the account to grant permissions. |
Source Code
function addAdmin(address _admin) public onlyOwner {
admins[_admin] = true;
emit AdminAdded(_admin);
}
Remove account from ACL.
function removeAdmin(address _admin) public nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
_admin | address | The addresses of the account to revoke permissions. |
Source Code
function removeAdmin(address _admin) public onlyOwner {
admins[_admin] = false;
emit AdminRemoved(_admin);
}
cSOV payout to sender with rBTC currency. 1.- Check holder cSOV balance by adding up every cSOV token balance. 2.- ReImburse rBTC if funds available. 3.- And store holder address in processedList.
function reImburse() public nonpayable isNotProcessed isNotBlacklisted
Source Code
function reImburse() public isNotProcessed isNotBlacklisted {
uint256 CSOVAmountWei = 0;
for (uint256 i = 0; i < CSOVtokens.length; i++) {
address CSOV = CSOVtokens[i];
uint256 balance = IERC20(CSOV).balanceOf(msg.sender);
CSOVAmountWei = CSOVAmountWei.add(balance);
}
require(CSOVAmountWei > lockedAmount[msg.sender], "holder has no CSOV");
CSOVAmountWei -= lockedAmount[msg.sender];
processedList[msg.sender] = true;
/**
* @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.
* More details at Documenting Code issues at point 11 in
* https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/
* Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);
* */
uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);
require(address(this).balance >= reImburseAmount, "Not enough funds to reimburse");
msg.sender.transfer(reImburseAmount);
emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);
}
Get contract balance.
function budget() external view
returns(uint256)
Source Code
function budget() external view returns (uint256) {
uint256 SCBudget = address(this).balance;
return SCBudget;
}
Deposit function to receiving value (rBTC).
function deposit() public payable
Source Code
function deposit() public payable {}
Send all contract balance to an account.
function withdrawAll(address payable to) public nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
to | address payable | The account address to send the balance to. |
Source Code
function withdrawAll(address payable to) public onlyOwner {
to.transfer(address(this).balance);
}
Sets vesting factory address. High level endpoint.
function setVestingFactory(address _vestingFactory) public nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
_vestingFactory | address | The address of vesting factory contract. * |
Source Code
function setVestingFactory(address _vestingFactory) public onlyOwner {
_setVestingFactory(_vestingFactory);
}
Sets vesting factory address. Low level core function.
function _setVestingFactory(address _vestingFactory) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
_vestingFactory | address | The address of vesting factory contract. |
Source Code
function _setVestingFactory(address _vestingFactory) internal {
require(_vestingFactory != address(0), "vestingFactory address invalid");
vestingFactory = IVestingFactory(_vestingFactory);
}
Sets cSOV tokens array. High level endpoint.
function setCSOVtokens(address[] _CSOVtokens) public nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
_CSOVtokens | address[] | The array of cSOV tokens. |
Source Code
function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {
_setCSOVtokens(_CSOVtokens);
}
Sets cSOV tokens array by looping through input. Low level function.
function _setCSOVtokens(address[] _CSOVtokens) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
_CSOVtokens | address[] | The array of cSOV tokens. |
Source Code
function _setCSOVtokens(address[] memory _CSOVtokens) internal {
for (uint256 i = 0; i < _CSOVtokens.length; i++) {
require(_CSOVtokens[i] != address(0), "CSOV address invalid");
}
CSOVtokens = _CSOVtokens;
}
Set blacklist flag (true/false).
function setBlacklistFlag(address _account, bool _blacklisted) public nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
_account | address | The address to be blacklisted. |
_blacklisted | bool | The flag to add/remove to/from a blacklist. |
Source Code
function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {
require(_account != address(0), "account address invalid");
blacklist[_account] = _blacklisted;
}
Set amount to be subtracted from user token balance.
function setLockedAmount(address _account, uint256 _amount) public nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
_account | address | The address with locked amount. |
_amount | uint256 | The amount to be locked. |
Source Code
function setLockedAmount(address _account, uint256 _amount) public onlyOwner {
require(_account != address(0), "account address invalid");
require(_amount != 0, "amount invalid");
lockedAmount[_account] = _amount;
}
Transfer SOV tokens to given address. *
function transferSOV(address _receiver, uint256 _amount) public nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
_receiver | address | The address of the SOV receiver. |
_amount | uint256 | The amount to be transferred. |
Source Code
function transferSOV(address _receiver, uint256 _amount) public onlyOwner {
require(_receiver != address(0), "receiver address invalid");
require(_amount != 0, "amount invalid");
IERC20(SOV).transfer(_receiver, _amount);
emit SOVTransferred(_receiver, _amount);
}
Exchange cSOV to SOV with 1:1 rate
function exchangeAllCSOV() public nonpayable isNotProcessed isNotBlacklisted
Source Code
function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {
processedList[msg.sender] = true;
uint256 amount = 0;
for (uint256 i = 0; i < CSOVtokens.length; i++) {
address CSOV = CSOVtokens[i];
uint256 balance = IERC20(CSOV).balanceOf(msg.sender);
amount += balance;
}
require(amount > lockedAmount[msg.sender], "amount invalid");
amount -= lockedAmount[msg.sender];
_createVestingForCSOV(amount);
}
cSOV tokens are moved and staked on Vesting contract.
function _createVestingForCSOV(uint256 _amount) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
_amount | uint256 | The amount of tokens to be vested. |
Source Code
function _createVestingForCSOV(uint256 _amount) internal {
address vesting =
_getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);
IERC20(SOV).approve(vesting, _amount);
IVesting(vesting).stakeTokens(_amount);
emit CSOVTokensExchanged(msg.sender, _amount);
}
Check a token address is among the cSOV token addresses.
function _validateCSOV(address _CSOV) internal view
Arguments
Name | Type | Description |
---|---|---|
_CSOV | address | The cSOV token address. |
Source Code
function _validateCSOV(address _CSOV) internal view {
bool isValid = false;
for (uint256 i = 0; i < CSOVtokens.length; i++) {
if (_CSOV == CSOVtokens[i]) {
isValid = true;
break;
}
}
require(isValid, "wrong CSOV address");
}
Create Vesting contract.
function createVesting(address _tokenOwner, uint256 _amount, uint256 _cliff, uint256 _duration) public nonpayable onlyAuthorized
Arguments
Name | Type | Description |
---|---|---|
_tokenOwner | address | The owner of the tokens. |
_amount | uint256 | The amount to be staked. |
_cliff | uint256 | The time interval to the first withdraw in seconds. |
_duration | uint256 | The total duration in seconds. |
Source Code
function createVesting(
address _tokenOwner,
uint256 _amount,
uint256 _cliff,
uint256 _duration
) public onlyAuthorized {
address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);
emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);
}
Create Team Vesting contract.
function createTeamVesting(address _tokenOwner, uint256 _amount, uint256 _cliff, uint256 _duration) public nonpayable onlyAuthorized
Arguments
Name | Type | Description |
---|---|---|
_tokenOwner | address | The owner of the tokens. |
_amount | uint256 | The amount to be staked. |
_cliff | uint256 | The time interval to the first withdraw in seconds. |
_duration | uint256 | The total duration in seconds. |
Source Code
function createTeamVesting(
address _tokenOwner,
uint256 _amount,
uint256 _cliff,
uint256 _duration
) public onlyAuthorized {
address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);
emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);
}
Stake tokens according to the vesting schedule.
function stakeTokens(address _vesting, uint256 _amount) public nonpayable onlyAuthorized
Arguments
Name | Type | Description |
---|---|---|
_vesting | address | The address of Vesting contract. |
_amount | uint256 | The amount of tokens to stake. |
Source Code
function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {
require(_vesting != address(0), "vesting address invalid");
require(_amount > 0, "amount invalid");
IERC20(SOV).approve(_vesting, _amount);
IVesting(_vesting).stakeTokens(_amount);
emit TokensStaked(_vesting, _amount);
}
Query the vesting contract for an account.
function getVesting(address _tokenOwner) public view
returns(address)
Arguments
Name | Type | Description |
---|---|---|
_tokenOwner | address | The owner of the tokens. |
Returns
The vesting contract address for the given token owner.
Source Code
function getVesting(address _tokenOwner) public view returns (address) {
return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];
}
Query the team vesting contract for an account.
function getTeamVesting(address _tokenOwner) public view
returns(address)
Arguments
Name | Type | Description |
---|---|---|
_tokenOwner | address | The owner of the tokens. |
Returns
The team vesting contract address for the given token owner.
Source Code
function getTeamVesting(address _tokenOwner) public view returns (address) {
return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];
}
If not exists, deploy a vesting contract through factory.
function _getOrCreateVesting(address _tokenOwner, uint256 _cliff, uint256 _duration) internal nonpayable
returns(address)
Arguments
Name | Type | Description |
---|---|---|
_tokenOwner | address | The owner of the tokens. |
_cliff | uint256 | The time interval to the first withdraw in seconds. |
_duration | uint256 | The total duration in seconds. |
Returns
The vesting contract address for the given token owner whether it existed previously or not.
Source Code
function _getOrCreateVesting(
address _tokenOwner,
uint256 _cliff,
uint256 _duration
) internal returns (address) {
uint256 type_ = uint256(VestingType.Vesting);
if (vestingContracts[_tokenOwner][type_] == address(0)) {
/// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.
address vesting =
vestingFactory.deployVesting(
SOV,
staking,
_tokenOwner,
_cliff,
_duration,
feeSharingCollector,
_tokenOwner
);
vestingContracts[_tokenOwner][type_] = vesting;
}
return vestingContracts[_tokenOwner][type_];
}
If not exists, deploy a team vesting contract through factory.
function _getOrCreateTeamVesting(address _tokenOwner, uint256 _cliff, uint256 _duration) internal nonpayable
returns(address)
Arguments
Name | Type | Description |
---|---|---|
_tokenOwner | address | The owner of the tokens. |
_cliff | uint256 | The time interval to the first withdraw in seconds. |
_duration | uint256 | The total duration in seconds. |
Returns
The team vesting contract address for the given token owner whether it existed previously or not.
Source Code
function _getOrCreateTeamVesting(
address _tokenOwner,
uint256 _cliff,
uint256 _duration
) internal returns (address) {
uint256 type_ = uint256(VestingType.TeamVesting);
if (vestingContracts[_tokenOwner][type_] == address(0)) {
address vesting =
vestingFactory.deployTeamVesting(
SOV,
staking,
_tokenOwner,
_cliff,
_duration,
feeSharingCollector,
vestingOwner
);
vestingContracts[_tokenOwner][type_] = vesting;
}
return vestingContracts[_tokenOwner][type_];
}
- 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