ETH Price: $3,178.31 (-3.33%)

Contract Diff Checker

Contract Name:
Vesting

Contract Source Code:

File 1 of 1 : Vesting

pragma solidity ^0.6.12;

/* SPDX-License-Identifier: UNLICENSED */

// ----------------------------------------------------------------------------
// Safe maths
// ----------------------------------------------------------------------------
library SafeMath {
    function add(uint a, uint b) internal pure returns (uint c) {
        c = a + b;
        require(c >= a);
    }
    function sub(uint a, uint b) internal pure returns (uint c) {
        require(b <= a);
        c = a - b;
    }
    function mul(uint a, uint b) internal pure returns (uint c) {
        c = a * b;
        require(a == 0 || c / a == b);
    }
    function div(uint a, uint b) internal pure returns (uint c) {
        require(b > 0);
        c = a / b;
    }
}

// ----------------------------------------------------------------------------
// Owned contract
// ----------------------------------------------------------------------------
contract Owned {
    address public owner;
    address public newOwner;

    event OwnershipTransferred(address indexed _from, address indexed _to);

    constructor() public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    function transferOwnership(address _newOwner) public onlyOwner {
        newOwner = _newOwner;
    }

    function acceptOwnership() public {
        require(msg.sender == newOwner);
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
        newOwner = address(0);
    }
}

// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
// ----------------------------------------------------------------------------
abstract contract ERC20Interface {
    function totalSupply() virtual public view returns (uint);
    function balanceOf(address tokenOwner) virtual public view returns (uint balance);
    function allowance(address tokenOwner, address spender) virtual public view returns (uint remaining);
    function transfer(address to, uint tokens) virtual public returns (bool success);
    function approve(address spender, uint tokens) virtual public returns (bool success);
    function transferFrom(address from, address to, uint tokens) virtual public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}


struct Schedule {
    uint32  start;
    uint32  length;
    uint256 initial;
    uint256 tokens;
}


contract Vesting is Owned, ERC20Interface {
    using SafeMath for uint;

    string public symbol;
    string public  name;
    uint8 public decimals;

    mapping(address => Schedule) public schedules;
    mapping(address => uint256) balances;
    address public lockedTokenAddress;


    // ------------------------------------------------------------------------
    // Constructor
    // ------------------------------------------------------------------------
    constructor() public {
        symbol = "VTLM";
        name = "Vesting Alien Worlds Trilium";
        decimals = 4;
    }

    /* ERC-20 functions, null most of them */

    function balanceOf(address tokenOwner) override virtual public view returns (uint balance) {
        return balances[tokenOwner];
    }

    function totalSupply() override virtual public view returns (uint) {
        return 0;
    }

    function allowance(address tokenOwner, address spender) override virtual public view returns (uint remaining){
        return 0;
    }

    function transfer(address to, uint tokens) override virtual public returns (bool success) {
        require(false, "Use the claim function, not transfer");
    }

    function approve(address spender, uint tokens) override virtual public returns (bool success) {
        require(false, "Cannot approve spending");
    }

    function transferFrom(address from, address to, uint tokens) override virtual public returns (bool success) {
        require(false, "Use the claim function, not transferFrom");
    }


    /* My functions */

    function vestedTotal(address user) private view returns (uint256){
        uint256 time_now = block.timestamp;
        uint256 vesting_seconds = 0;
        Schedule memory s = schedules[user];

        uint256 vested_total = balances[user];

        if (s.start > 0) {
            if (time_now >= s.start) {
                vesting_seconds = time_now - s.start;

                uint256 vest_per_second_sats = s.tokens.sub(s.initial);
                vest_per_second_sats = vest_per_second_sats.div(s.length);
                
                vested_total = vesting_seconds.mul(vest_per_second_sats);
                vested_total = vested_total.add(s.initial); // amount they can withdraw
            }
            else {
                vested_total = 1;
            }
            
            if (vested_total > s.tokens) {
                vested_total = s.tokens;
            }
        }

        return vested_total;
    }

    function maxClaim(address user) public view returns (uint256) {
        uint256 vested_total = vestedTotal(user);
        Schedule memory s = schedules[user];
        uint256 max = 0;

        if (s.start > 0){
            uint256 claimed = s.tokens.sub(balances[user]);

            max = vested_total.sub(claimed);

            if (max > balances[user]){
                max = balances[user];
            }
        }

        return max;
    }

    function claim(uint256 amount) public {
        require(lockedTokenAddress != address(0x0), "Locked token contract has not been set");
        require(amount > 0, "Must claim more than 0");
        require(balances[msg.sender] > 0, "No vesting balance found");

        uint256 vested_total = vestedTotal(msg.sender);

        Schedule memory s = schedules[msg.sender];
        if (s.start > 0){
            uint256 remaining_balance = balances[msg.sender].sub(amount);

            if (vested_total < s.tokens) {
                uint min_balance = s.tokens.sub(vested_total);
                require(remaining_balance >= min_balance, "Cannot transfer this amount due to vesting locks");
            }
        }

        balances[msg.sender] = balances[msg.sender].sub(amount);
        ERC20Interface(lockedTokenAddress).transfer(msg.sender, amount);
    }

    function setSchedule(address user, uint32 start, uint32 length, uint256 initial, uint256 amount) public onlyOwner {
        schedules[user].start = start;
        schedules[user].length = length;
        schedules[user].initial = initial;
        schedules[user].tokens = amount;
    }

    function addTokens(address newOwner, uint256 amount) public onlyOwner {
        require(lockedTokenAddress != address(0x0), "Locked token contract has not been set");

        ERC20Interface tokenContract = ERC20Interface(lockedTokenAddress);

        uint256 userAllowance = tokenContract.allowance(msg.sender, address(this));
        uint256 fromBalance = tokenContract.balanceOf(msg.sender);
        require(fromBalance >= amount, "Sender has insufficient balance");
        require(userAllowance >= amount, "Please allow tokens to be spent by this contract");
        tokenContract.transferFrom(msg.sender, address(this), amount);

        balances[newOwner] = balances[newOwner].add(amount);
        
        emit Transfer(address(0x0), newOwner, amount);
    }

    function removeTokens(address owner, uint256 amount) public onlyOwner {
        ERC20Interface tokenContract = ERC20Interface(lockedTokenAddress);
        tokenContract.transfer(owner, amount);
        
        balances[owner] = balances[owner].sub(amount);
    }

    function setTokenContract(address _lockedTokenAddress) public onlyOwner {
        lockedTokenAddress = _lockedTokenAddress;
    }

    // ------------------------------------------------------------------------
    // Don't accept ETH
    // ------------------------------------------------------------------------
    receive () external payable {
        revert();
    }


    // ------------------------------------------------------------------------
    // Owner can transfer out any accidentally sent ERC20 tokens
    // ------------------------------------------------------------------------
    function transferAnyERC20Token(address tokenAddress, uint256 tokens) public onlyOwner returns (bool success) {
        return ERC20Interface(tokenAddress).transfer(owner, tokens);
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):