pragma solidity 0.4.24;

/// @title SafeMath
/// @dev Math operations with safety checks that throw on error
library SafeMath {

    /// @dev Multiply two numbers, throw on overflow.
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        if (a == 0) {
            return 0;
        }
        c = a * b;
        assert(c / a == b);
        return c;
    }

    /// @dev Substract two numbers, throw on overflow (i.e. if subtrahend is greater than minuend).
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    /// @dev Add two numbers, throw on overflow.
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }
}

/// @title Ownable
/// @dev Provide a modifier that permits only a single user to call the function
contract Ownable {
    address public owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// @dev Set the original `owner` of the contract to the sender account.
    constructor() public {
        owner = msg.sender;
    }

    /// @dev Require that the modified function is only called by `owner`
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    /// @dev Allow `owner` to transfer control of the contract to `newOwner`.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0));
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

}

/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/179
 */
contract ERC20Basic {
  function totalSupply() public view returns (uint256);
  function balanceOf(address who) public view returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender)
    public view returns (uint256);

  function transferFrom(address from, address to, uint256 value)
    public returns (bool);

  function approve(address spender, uint256 value) public returns (bool);
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}

/**
 * @title Contracts that should not own Ether
 * @author Remco Bloemen <remco@2π.com>
 * @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up
 * in the contract, it will allow the owner to reclaim this ether.
 * @notice Ether can still be sent to this contract by:
 * calling functions labeled `payable`
 * `selfdestruct(contract_address)`
 * mining directly to the contract address
 */
contract HasNoEther is Ownable {

    /**
    * @dev Constructor that rejects incoming Ether
    * @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we
    * leave out payable, then Solidity will allow inheriting contracts to implement a payable
    * constructor. By doing it this way we prevent a payable constructor from working. Alternatively
    * we could use assembly to access msg.value.
    */
    constructor() public payable {
        require(msg.value == 0);
    }

    /**
    * @dev Disallows direct send by settings a default function without the `payable` flag.
    */
    function() external {}

    /**
    * @dev Transfer all Ether held by the contract to the owner.
    */
    function reclaimEther() external onlyOwner {
        owner.transfer(address(this).balance);
    }
}

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
  function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
    require(token.transfer(to, value));
  }

  function safeTransferFrom(
    ERC20 token,
    address from,
    address to,
    uint256 value
  )
    internal
  {
    require(token.transferFrom(from, to, value));
  }

  function safeApprove(ERC20 token, address spender, uint256 value) internal {
    require(token.approve(spender, value));
  }
}

/**
 * @title Contracts that should be able to recover tokens
 * @author SylTi
 * @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner.
 * This will prevent any accidental loss of tokens.
 */
contract CanReclaimToken is Ownable {
  using SafeERC20 for ERC20Basic;

  /**
   * @dev Reclaim all ERC20Basic compatible tokens
   * @param token ERC20Basic The address of the token contract
   */
  function reclaimToken(ERC20Basic token) external onlyOwner {
    uint256 balance = token.balanceOf(this);
    token.safeTransfer(owner, balance);
  }

}

/**
 * @title Contracts that should not own Tokens
 * @author Remco Bloemen <remco@2π.com>
 * @dev This blocks incoming ERC223 tokens to prevent accidental loss of tokens.
 * Should tokens (any ERC20Basic compatible) end up in the contract, it allows the
 * owner to reclaim the tokens.
 */
contract HasNoTokens is CanReclaimToken {

 /**
  * @dev Reject all ERC223 compatible tokens
  * @param from_ address The address that is transferring the tokens
  * @param value_ uint256 the amount of the specified token
  * @param data_ Bytes The data passed from the caller.
  */
  function tokenFallback(address from_, uint256 value_, bytes data_) external {
    from_;
    value_;
    data_;
    revert();
  }

}

/**
 * @title Contracts that should not own Contracts
 * @author Remco Bloemen <remco@2π.com>
 * @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner
 * of this contract to reclaim ownership of the contracts.
 */
contract HasNoContracts is Ownable {

    /**
    * @dev Reclaim ownership of Ownable contracts
    * @param contractAddr The address of the Ownable to be reclaimed.
    */
    function reclaimContract(address contractAddr) external onlyOwner {
        Ownable contractInst = Ownable(contractAddr);
        contractInst.transferOwnership(owner);
    }
}

/**
 * @title Base contract for contracts that should not own things.
 * @author Remco Bloemen <remco@2π.com>
 * @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or
 * Owned contracts. See respective base contracts for details.
 */
contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts {
}

/**
 * @title Basic token
 * @dev Basic version of StandardToken, with no allowances.
 */
contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  mapping(address => uint256) balances;

  uint256 totalSupply_;

  /**
  * @dev total number of tokens in existence
  */
  function totalSupply() public view returns (uint256) {
    return totalSupply_;
  }

  /**
  * @dev transfer token for a specified address
  * @param _to The address to transfer to.
  * @param _value The amount to be transferred.
  */
  function transfer(address _to, uint256 _value) public returns (bool) {
    require(_to != address(0));
    require(_value <= balances[msg.sender]);

    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param _owner The address to query the the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address _owner) public view returns (uint256) {
    return balances[_owner];
  }

}

/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * @dev https://github.com/ethereum/EIPs/issues/20
 * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
contract StandardToken is ERC20, BasicToken {

  mapping (address => mapping (address => uint256)) internal allowed;


  /**
   * @dev Transfer tokens from one address to another
   * @param _from address The address which you want to send tokens from
   * @param _to address The address which you want to transfer to
   * @param _value uint256 the amount of tokens to be transferred
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _value
  )
    public
    returns (bool)
  {
    require(_to != address(0));
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);

    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    emit Transfer(_from, _to, _value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   *
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param _spender The address which will spend the funds.
   * @param _value The amount of tokens to be spent.
   */
  function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param _owner address The address which owns the funds.
   * @param _spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(
    address _owner,
    address _spender
   )
    public
    view
    returns (uint256)
  {
    return allowed[_owner][_spender];
  }

  /**
   * @dev Increase the amount of tokens that an owner allowed to a spender.
   *
   * approve should be called when allowed[_spender] == 0. To increment
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param _spender The address which will spend the funds.
   * @param _addedValue The amount of tokens to increase the allowance by.
   */
  function increaseApproval(
    address _spender,
    uint _addedValue
  )
    public
    returns (bool)
  {
    allowed[msg.sender][_spender] = (
      allowed[msg.sender][_spender].add(_addedValue));
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

  /**
   * @dev Decrease the amount of tokens that an owner allowed to a spender.
   *
   * approve should be called when allowed[_spender] == 0. To decrement
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param _spender The address which will spend the funds.
   * @param _subtractedValue The amount of tokens to decrease the allowance by.
   */
  function decreaseApproval(
    address _spender,
    uint _subtractedValue
  )
    public
    returns (bool)
  {
    uint oldValue = allowed[msg.sender][_spender];
    if (_subtractedValue > oldValue) {
      allowed[msg.sender][_spender] = 0;
    } else {
      allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    }
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

}

/// @title Lockable token with exceptions
/// @dev StandardToken modified with pausable transfers.
contract LockableToken is Ownable, StandardToken {

    /// Flag for locking normal trading
    bool public locked = true;

    /// Addresses exempted from token trade lock
    mapping(address => bool) public lockExceptions;

    constructor() public {
        // It should always be possible to call reclaimToken
        lockExceptions[this] = true;
    }

    /// @notice Admin function to lock trading
    function lock() public onlyOwner {
        locked = true;
    }

    /// @notice Admin function to unlock trading
    function unlock() public onlyOwner {
        locked = false;
    }

    /// @notice Set whether `sender` may trade when token is locked
    /// @param sender The address to change the lock exception for
    /// @param _canTrade Whether `sender` may trade
    function setTradeException(address sender, bool _canTrade) public onlyOwner {
        lockExceptions[sender] = _canTrade;
    }

    /// @notice Check if the token is currently tradable for `sender`
    /// @param sender The address attempting to make a transfer
    /// @return True if `sender` is allowed to make transfers, false otherwise
    function canTrade(address sender) public view returns(bool) {
        return !locked || lockExceptions[sender];
    }

    /// @dev Modifier to make a function callable only when the contract is not paused.
    modifier whenNotLocked() {
        require(canTrade(msg.sender));
        _;
    }

    function transfer(address _to, uint256 _value)
                public whenNotLocked returns (bool) {

        return super.transfer(_to, _value);
    }

    function transferFrom(address _from, address _to, uint256 _value)
                public whenNotLocked returns (bool) {

        return super.transferFrom(_from, _to, _value);
    }

    function approve(address _spender, uint256 _value)
                public whenNotLocked returns (bool) {

        return super.approve(_spender, _value);
    }

    function increaseApproval(address _spender, uint _addedValue)
                public whenNotLocked returns (bool success) {

        return super.increaseApproval(_spender, _addedValue);
    }

    function decreaseApproval(address _spender, uint _subtractedValue)
                public whenNotLocked returns (bool success) {
                        
        return super.decreaseApproval(_spender, _subtractedValue);
    }
}

/// @title Pledgecamp Token (PLG)
/// @author Sam Pullman
/// @notice ERC20 compatible token for the Pledgecamp platform
contract PLGToken is Ownable, NoOwner, LockableToken {
    using SafeMath for uint256;
    
    /// @notice Emitted when tokens are burned
    /// @param burner Account that burned its tokens
    /// @param value Number of tokens burned
    event Burn(address indexed burner, uint256 value);

    string public name = "PLGToken";
    string public symbol = "PLG";
    uint8 public decimals = 18;

    /// Flag for only allowing a single token initialization
    bool public initialized = false;

    /// @notice Set initial PLG allocations, which can only happen once
    /// @param addresses Addresses of beneficiaries
    /// @param allocations Amounts to allocate each beneficiary
    function initialize(address[] addresses, uint256[] allocations) public onlyOwner {
        require(!initialized);
        require(addresses.length == allocations.length);
        initialized = true;

        for(uint i = 0; i<allocations.length; i += 1) {
            require(addresses[i] != address(0));
            require(allocations[i] > 0);
            balances[addresses[i]] = allocations[i];
            totalSupply_ = totalSupply_.add(allocations[i]);
        }
    }

    /// @dev Burns a specific amount of tokens owned by the sender
    /// @param value The number of tokens to be burned
    function burn(uint256 value) public {
        require(value <= balances[msg.sender]);

        balances[msg.sender] = balances[msg.sender].sub(value);
        totalSupply_ = totalSupply_.sub(value);
        emit Burn(msg.sender, value);
        emit Transfer(msg.sender, address(0), value);
    }

}

/// @notice Abstract contract for vesting schedule
/// @notice Implementations must provide vestedPercent()
contract Schedule is Ownable {
    using SafeMath for uint256;

    /// The timestamp of the start of vesting
    uint256 public tokenReleaseDate;

    /// The timestamp of the vesting release interval
    uint256 public releaseInterval = 30 days;

    constructor(uint256 _tokenReleaseDate) public {
        tokenReleaseDate = _tokenReleaseDate;
    }

    /// @notice Update the date that PLG trading unlocks
    /// @param newReleaseDate The new PLG release timestamp
    function setTokenReleaseDate(uint256 newReleaseDate) public onlyOwner {
        tokenReleaseDate = newReleaseDate;
    }

    /// @notice Calculates the percent of tokens that may be claimed at this time
    /// @return Number of tokens vested
    function vestedPercent() public view returns (uint256);

    /// @notice Helper for calculating the time of a specific release
    /// @param intervals The number of interval periods to calculate a release date for
    /// @return The timestamp of the release date
    function getReleaseTime(uint256 intervals) public view returns (uint256) {
        return tokenReleaseDate.add(releaseInterval.mul(intervals));
    }
}

/// @notice Abstract contract for vesting PLGTokens
contract TokenVesting is Ownable {
    using SafeMath for uint256;

    /// @notice Emitted when tokens are released to the beneficiary
    /// @param amount The number of tokens released
    event Released(uint256 amount);

    /// @notice Emitted if the vesting contract is revoked
    event Revoked();

    /// Vested tokens originate from this ERC20 token contract 
    PLGToken token;

    /// Helper contract that determines the vesting schedule
    Schedule schedule;

    /// The beneficiary of the vesting schedule
    address public beneficiary;

    /// Number of tokens released to `beneficiary` from token contracts
    uint256 public released;

    /// Whether the vesting contract is revoked for a given token contract
    bool public revoked = false;

    /// @param _beneficiary The account that receives vested tokens
    /// @param _token The address of the ERC20 token contract
    /// @param _schedule The address of the vesting schedule
    constructor(address _token, address _beneficiary, address _schedule) public {
        beneficiary = _beneficiary;
        token = PLGToken(_token);
        schedule = Schedule(_schedule);
    }

    /// @notice Disallow receiving ether using a default function with no `payable` flag.
    function() external {}

    /// @notice Transfer vested tokens to beneficiary.
    function release() public {
        require(!revoked);
        require((msg.sender == owner) || (msg.sender == beneficiary));
        
        uint256 unreleased = releasableAmount();
        require(unreleased > 0);

        released = released.add(unreleased);

        token.transfer(beneficiary, unreleased);

        emit Released(unreleased);
    }

    /// @notice Allow the owner to revoke the vesting. Tokens already vested
    ///  remain in the contract, the rest are returned to the owner.
    function revoke() public onlyOwner {
        require(!revoked);

        uint256 balance = token.balanceOf(this);

        uint256 unreleased = releasableAmount();
        uint256 refund = balance.sub(unreleased);

        revoked = true;

        token.transfer(owner, refund);

        emit Revoked();
    }

    /// @notice Alternative to revoke() that sends all tokens to owner and self destructs
    function kill() public onlyOwner {

        uint256 balance = token.balanceOf(this);
        token.transfer(owner, balance);
        selfdestruct(owner);
    }

    /// @notice Calculates the amount that has already vested but hasn't been released yet.
    /// @return Number of releasable tokens
    function releasableAmount() public view returns (uint256) {
        if(revoked) {
            return 0;
        }
        uint256 tokens = token.balanceOf(this);
        uint256 totalBalance = released.add(tokens);
        uint256 releasePercent = schedule.vestedPercent();
        uint256 totalRelease = totalBalance.mul(releasePercent) / 100;

        // Account for situation where vesting schedule is disabled after
        // some tokens have already been released
        if(totalRelease >= released) {
            return totalRelease.sub(released);
        } else {
            return 0;
        }
    }
}