function withdraw() external {
    require(!allocations[msg.sender].hasWithdrawn);
    
    require(block.timestamp > SimpleTGEContract.publicTGEEndBlockTimeStamp().add(SimpleTGEContract.TRSOffset()));
    
    require(SimplePreTGEContract.allocationsLocked());
    
    bool _preTGEHasVested;
    uint256 _preTGEWeiContributed;
    bool _publicTGEHasVested;
    uint256 _publicTGEWeiContributed;
    (_publicTGEHasVested, _publicTGEWeiContributed) = SimpleTGEContract.contributions(msg.sender);
    (_preTGEHasVested, _preTGEWeiContributed) = SimplePreTGEContract.contributions(msg.sender);
    uint256 _totalWeiContribution = _preTGEWeiContributed.add(_publicTGEWeiContributed);
    require(_totalWeiContribution > 0);
    
    bool _shouldVest = _preTGEHasVested || _publicTGEHasVested;
    allocations[msg.sender].hasWithdrawn = true;
    allocations[msg.sender].shouldVest = _shouldVest;
    allocations[msg.sender].weiContributed = _totalWeiContribution;
    uint256 _lstAllocated;
    if (!_shouldVest) {
      _lstAllocated = LSTRatePerWEI.mul(_totalWeiContribution);
      allocations[msg.sender].LSTAllocated = _lstAllocated;
      require(token.mint(msg.sender, _lstAllocated));
      LogLSTsWithdrawn(msg.sender, _lstAllocated);
    }
    else {
      _lstAllocated = LSTRatePerWEI.mul(_totalWeiContribution).mul(vestingBonusMultiplier).div(vestingBonusMultiplierPrecision);
      allocations[msg.sender].LSTAllocated = _lstAllocated;
      uint256 _withdrawNow = _lstAllocated.div(10);
      uint256 _vestedPortion = _lstAllocated.sub(_withdrawNow);
      vesting[msg.sender] = new TokenVesting(msg.sender, vestingStartTime, 0, vestingDuration, false);
      require(token.mint(msg.sender, _withdrawNow));
      LogLSTsWithdrawn(msg.sender, _withdrawNow);
      require(token.mint(address(vesting[msg.sender]), _vestedPortion));
      LogTimeVestingLSTsWithdrawn(address(vesting[msg.sender]), _vestedPortion, vestingStartTime, 0, vestingDuration);
    }
  }