Skip to content

Commit

Permalink
Merge pull request #417 from DistributedCollective/four-year-vesting
Browse files Browse the repository at this point in the history
Four Year Vesting
  • Loading branch information
ororopickpocket authored Jun 14, 2022
2 parents e43b13e + a990eb6 commit 8cc1cde
Show file tree
Hide file tree
Showing 20 changed files with 2,357 additions and 6 deletions.
51 changes: 51 additions & 0 deletions .github/workflows/extendstakingcron.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Extend Staking

on:
schedule:
# The cron job should run every four weeks from the creation of four year vesting contract
# and only for 52 weeks
- cron: "30 10 * * FRI"

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Setup node.js
uses: actions/setup-node@v1
with:
node-version: "14.x"
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Cache compiler installations
uses: actions/cache@v2
with:
path: |
~/.solcx
~/.vvm
key: ${{ runner.os }}-compiler-cache

- name: Install python dependencies
run: pip install -r requirements.txt

- name: Extend Staking
run: echo $REWARDS_CRON && brownie networks import network-config.yaml true && brownie run scripts/fouryearvesting/extendStakingCron.py --network=rsk-mainnet
env:
REWARDS_CRON: 1
FEE_CLAIMER: ${{secrets.FEE_CLAIMER}}
39 changes: 39 additions & 0 deletions contracts/governance/Vesting/VestingRegistryLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,45 @@ contract VestingRegistryLogic is VestingRegistryStorage {
}
}

/**
* @notice adds four year vestings to vesting registry logic
* @param _tokenOwners array of token owners
* @param _vestingAddresses array of vesting addresses
*/
function addFourYearVestings(
address[] calldata _tokenOwners,
address[] calldata _vestingAddresses
) external onlyAuthorized {
require(_tokenOwners.length == _vestingAddresses.length, "arrays mismatch");
uint256 vestingCreationType = 4;
uint256 cliff = 4 weeks;
uint256 duration = 156 weeks;
for (uint256 i = 0; i < _tokenOwners.length; i++) {
require(!isVesting[_vestingAddresses[i]], "vesting exists");
require(_tokenOwners[i] != address(0), "token owner cannot be 0 address");
require(_vestingAddresses[i] != address(0), "vesting cannot be 0 address");
uint256 uid =
uint256(
keccak256(
abi.encodePacked(
_tokenOwners[i],
uint256(VestingType.Vesting),
cliff,
duration,
vestingCreationType
)
)
);
vestings[uid] = Vesting(
uint256(VestingType.Vesting),
vestingCreationType,
_vestingAddresses[i]
);
vestingsOf[_tokenOwners[i]].push(uid);
isVesting[_vestingAddresses[i]] = true;
}
}

/**
* @notice creates Vesting contract
* @param _tokenOwner the owner of the tokens
Expand Down
72 changes: 72 additions & 0 deletions contracts/governance/Vesting/fouryear/FourYearVesting.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
pragma solidity ^0.5.17;
pragma experimental ABIEncoderV2;

import "../../../openzeppelin/Ownable.sol";
import "../../../interfaces/IERC20.sol";
import "../../Staking/Staking.sol";
import "../../IFeeSharingProxy.sol";
import "../../ApprovalReceiver.sol";
import "./FourYearVestingStorage.sol";
import "../../../proxy/UpgradableProxy.sol";
import "../../../openzeppelin/Address.sol";

/**
* @title Four Year Vesting Contract.
*
* @notice A four year vesting contract.
*
* @dev Vesting contract is upgradable,
* Make sure the vesting owner is multisig otherwise it will be
* catastrophic.
* */
contract FourYearVesting is FourYearVestingStorage, UpgradableProxy {
/**
* @notice Setup the vesting schedule.
* @param _logic The address of logic contract.
* @param _SOV The SOV token address.
* @param _tokenOwner The owner of the tokens.
* @param _feeSharingProxy Fee sharing proxy address.
* @param _extendDurationFor Duration till the unlocked tokens are extended.
* */
constructor(
address _logic,
address _SOV,
address _stakingAddress,
address _tokenOwner,
address _feeSharingProxy,
uint256 _extendDurationFor
) public {
require(Address.isContract(_logic), "_logic not a contract");
require(_SOV != address(0), "SOV address invalid");
require(Address.isContract(_SOV), "_SOV not a contract");
require(_stakingAddress != address(0), "staking address invalid");
require(Address.isContract(_stakingAddress), "_stakingAddress not a contract");
require(_tokenOwner != address(0), "token owner address invalid");
require(_feeSharingProxy != address(0), "feeSharingProxy address invalid");
require(Address.isContract(_feeSharingProxy), "_feeSharingProxy not a contract");
require((_extendDurationFor % FOUR_WEEKS) == 0, "invalid duration");

_setImplementation(_logic);
SOV = IERC20(_SOV);
staking = Staking(_stakingAddress);
tokenOwner = _tokenOwner;
feeSharingProxy = IFeeSharingProxy(_feeSharingProxy);
maxInterval = 18 * FOUR_WEEKS;
extendDurationFor = _extendDurationFor;
}

/**
* @notice Set address of the implementation - vesting owner.
* @dev Overriding setImplementation function of UpgradableProxy. The logic can only be
* modified when both token owner and veting owner approve. Since
* setImplementation can only be called by vesting owner, we also need to check
* if the new logic is already approved by the token owner.
* @param _implementation Address of the implementation. Must match with what is set by token owner.
* */
function setImplementation(address _implementation) public onlyProxyOwner {
require(Address.isContract(_implementation), "_implementation not a contract");
require(newImplementation == _implementation, "address mismatch");
_setImplementation(_implementation);
newImplementation = address(0);
}
}
52 changes: 52 additions & 0 deletions contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
pragma solidity ^0.5.17;

import "../../../openzeppelin/Ownable.sol";
import "./FourYearVesting.sol";
import "./IFourYearVestingFactory.sol";

/**
* @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.
* @notice Factory pattern allows to create multiple instances
* of the same contract and keep track of them easier.
* */
contract FourYearVestingFactory is IFourYearVestingFactory, Ownable {
/// @dev Added an event to keep track of the vesting contract created for a token owner
event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);

/**
* @notice Deploys four year vesting contract.
* @param _SOV the address of SOV token.
* @param _staking The address of staking contract.
* @param _tokenOwner The owner of the tokens.
* @param _feeSharing The address of fee sharing contract.
* @param _vestingOwnerMultisig The address of an owner of vesting contract.
* @dev _vestingOwnerMultisig should ALWAYS be multisig.
* @param _fourYearVestingLogic The implementation contract.
* @param _extendDurationFor Duration till the unlocked tokens are extended.
* @return The four year vesting contract address.
* */
function deployFourYearVesting(
address _SOV,
address _staking,
address _tokenOwner,
address _feeSharing,
address _vestingOwnerMultisig,
address _fourYearVestingLogic,
uint256 _extendDurationFor
) external onlyOwner returns (address) {
address fourYearVesting =
address(
new FourYearVesting(
_fourYearVestingLogic,
_SOV,
_staking,
_tokenOwner,
_feeSharing,
_extendDurationFor
)
);
Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);
emit FourYearVestingCreated(_tokenOwner, fourYearVesting);
return fourYearVesting;
}
}
Loading

0 comments on commit 8cc1cde

Please sign in to comment.