creation_sourcecode: // SPDX-License-Identifier: MIT
  pragma solidity ^0.8.12;
  
  interface IERC20 {
      function totalSupply() external view returns (uint256);
      function balanceOf(address account) external view returns (uint256);
      function transfer(address to, uint256 value) external returns (bool);
      function allowance(address owner, address spender) external view returns (uint256);
      function approve(address spender, uint256 value) external returns (bool);
      function transferFrom(address from, address to, uint256 value) external returns (bool);
  }
  
  interface IVXCHNG {
      function totalVXCHNGSupply() external view returns(uint256);
      function vXCHNGBalance(address)external view returns(uint256) ;
  }
  abstract contract Context {
      function _msgSender() internal view virtual returns (address) {
          return msg.sender;
      }
  
      function _msgData() internal view virtual returns (bytes calldata) {
          return msg.data;
      }
  
      function _contextSuffixLength() internal view virtual returns (uint256) {
          return 0;
      }
  }
  
  abstract contract Ownable is Context {
      address private _owner;
  
      error OwnableUnauthorizedAccount(address account);
      error OwnableInvalidOwner(address owner);
  
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      constructor(address initialOwner) {
          if (initialOwner == address(0)) {
              revert OwnableInvalidOwner(address(0));
          }
          _transferOwnership(initialOwner);
      }
  
      modifier onlyOwner() {
          _checkOwner();
          _;
      }
  
      function owner() public view virtual returns (address) {
          return _owner;
      }
  
      function _checkOwner() internal view virtual {
          if (owner() != _msgSender()) {
              revert OwnableUnauthorizedAccount(_msgSender());
          }
      }
  
      function renounceOwnership() public virtual onlyOwner {
          _transferOwnership(address(0));
      }
  
      function transferOwnership(address newOwner) public virtual onlyOwner {
          if (newOwner == address(0)) {
              revert OwnableInvalidOwner(address(0));
          }
          _transferOwnership(newOwner);
      }
  
      function _transferOwnership(address newOwner) internal virtual {
          address oldOwner = _owner;
          _owner = newOwner;
          emit OwnershipTransferred(oldOwner, newOwner);
      }
  }
  interface IWETH9{
      function withdraw(uint wad) external;
  }
  
  contract VShare is Ownable{
  
      mapping (uint256 => mapping (address =>uint256)) public totalTokenBalance;
  
      mapping (address => mapping (uint256 => mapping (address => uint256))) public userTokenDebt;
  
      address public VXCHNG;
  
      address public WETH;
  
      uint256 public currentPeriod;
  
      mapping (uint256 => bool) public claimEnabled;
  
      mapping (uint256 => mapping (address => uint256) ) public currentPeriodVXCHNGAmount;
  
      mapping (uint256 => mapping (address => uint256) ) public userVXCHNGBalance; 
  
      mapping (uint256 => uint256) public periodTotalVXCHNGSupply; 
  
      mapping (address => uint256 ) public userLastPeriod;
  
      constructor(
          address _vxchng,
          address _WETH,
          uint256 _firstPeriod
      ) Ownable(msg.sender) {
          VXCHNG = _vxchng;
          WETH = _WETH;
          currentPeriod = _firstPeriod;
      }
  
      receive() external payable {
          assert(msg.sender == WETH);
      }
  
      function setReward(uint256 _period, address _token, uint256 _amount) public onlyOwner {
          require(_amount > 0, "amount cannot be 0");
          IERC20(_token).transferFrom(msg.sender, address(this), _amount);
          totalTokenBalance[_period][_token] += _amount;
      }
  
      function enableClaim(uint256 _enablePeriod, uint256 _nextPeroid, bool _enable) public onlyOwner  {
          currentPeriod = _nextPeroid;
          claimEnabled[_enablePeriod] = _enable;
          periodTotalVXCHNGSupply[_enablePeriod] = IVXCHNG(VXCHNG).totalVXCHNGSupply();
      }
  
      function withdraw(uint256 _period, address _token, uint256 _amount) public onlyOwner {
           IERC20(_token).transfer(msg.sender, _amount);
           totalTokenBalance[_period][_token] -= _amount;
      }
  
      function claim(uint256 _period, address[] calldata _tokens) public {
          require(claimEnabled[_period], "claim not enabled yet");
          uint256 _vxchngTotal = periodTotalVXCHNGSupply[_period];
          require(_vxchngTotal > 0, "claim not enabled yet 2");
  
          for(uint i = 0; i< _tokens.length; i ++) {
              uint256 _debtAmount =  userTokenDebt[msg.sender][_period][_tokens[i]];
              require(_debtAmount == 0, "token received");
              uint256 _vxchngBalance = _period >= userLastPeriod[msg.sender] ? IVXCHNG(VXCHNG).vXCHNGBalance(msg.sender) : userVXCHNGBalance[_period][msg.sender];
              uint256 _totalBalance =  totalTokenBalance[_period][_tokens[i]];
              uint256 _amount = (_vxchngBalance * 1e30 / _vxchngTotal * _totalBalance) / 1e30;
              if (_amount == 0) {
                  continue;
              }
              if(_tokens[i] == WETH) {
                  IWETH9(WETH).withdraw(_amount);
                  safeTransferETH(msg.sender, _amount);
              }else{
                  IERC20(_tokens[i]).transfer(msg.sender, _amount);
              }
              userTokenDebt[msg.sender][_period][_tokens[i]] = _amount;
          }
      }
  
      function claimable(uint256 _period, address[] calldata _tokens, address _account) public view returns(uint256[] memory) {
          uint256[] memory _amounts =  new uint256[]( _tokens.length);
          uint256 _vxchngTotal = periodTotalVXCHNGSupply[_period];
          if(_vxchngTotal == 0) {
              return _amounts;
          }
          if( _period == currentPeriod) {
               return _amounts;
          }
          for(uint i = 0; i < _tokens.length; i++ ) {
              uint256 _vxchngBalance = _period >= userLastPeriod[_account] ? IVXCHNG(VXCHNG).vXCHNGBalance(_account) : userVXCHNGBalance[_period][_account];
              uint256 _totalBalance =  totalTokenBalance[_period][_tokens[i]];
              _amounts[i] = userTokenDebt[_account][_period][_tokens[i]] == 0 ? (_vxchngBalance * 1e30 / _vxchngTotal * _totalBalance) / 1e30 : 0;
          }
          return _amounts;
      }
  
      function safeTransferETH(address to, uint256 value) internal {
          (bool success, ) = to.call{value: value}(new bytes(0));
          require(success, 'transferHelper::safeTransferETH: ETH transfer failed');
      }
  
      function stake(address _account, uint256) public {
          require(msg.sender == VXCHNG, "only vxchng is allowed");
          userVXCHNGBalance[currentPeriod][_account] = IVXCHNG(VXCHNG).vXCHNGBalance(_account);
          userLastPeriod[_account] = currentPeriod;
      }
  
      function unstake(address, uint256) public virtual {
          require(msg.sender == VXCHNG, "only vxchng is allowed");
      }
  }