Contract Diff Checker

Contract Name:
VRMatrix

Contract Source Code:

File 1 of 1 : VRMatrix

// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;
// Ownable contract to manage contract ownership
contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor() {
        _transferOwnership(msg.sender);
    }

    function owner() public view returns (address) {
        return _owner;
    }

    modifier onlyOwner() {
        require(_owner == msg.sender, "Ownable: caller is not the owner");
        _;
    }

    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// ReentrancyGuard contract to prevent reentrancy attacks
contract ReentrancyGuard {
    uint256 private _status;
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}

// Interface for the registration contract

interface IREG {
    function NumberOfUsers() external view returns (uint256);
    function AddressToCountId(address user) external view returns (uint256);
    function countIdToAddress(uint id) external view returns (address);
    function isRegistered(address user) external view returns (bool);
    function userUpline(address user) external view returns (address);
}


contract VRMatrix is Ownable , ReentrancyGuard {

  // public variables-
    uint public numberOfActiveUsers;
    uint public totalEarned ;
    IREG public regContract;
    address public lastUser;


    uint public TOTAL_LEVELS = 10;

    constructor() {
     regContract = IREG(0xbbcd14B04924F33c303627578708fd4f51d39383); 
     levelPrice[1] = 5 ether ;

      for (uint i = 2; i < TOTAL_LEVELS ; i++ ) {
        levelPrice[i] = levelPrice[i - 1] * 2; // each price from 1 is 2X the last price

      }
     initOwner(); // initialize the constante variables and public variables with the values from the registry  
    }

       
       
    

     
    function initOwner() internal {
        address zeroAddress = address(0);
        lastUser = getFirstID();
        virtualUplineOf[lastUser] = zeroAddress ;
         
         users[lastUser] = User ({
         userAddress : lastUser,
         team_Id :  1 ,
         totalIncome : 0 ,
         totalVirtualIncome : 0 , 
         transactionCount : 0 , 
         totalDirect : 0 , 
         lastUpdate : block.timestamp ,
         currentUserLevel : TOTAL_LEVELS ,
         firstActivationDate : block.timestamp 

       }) ;


       userLevel[lastUser] = TOTAL_LEVELS ;
       virtualIds[lastUser] = numberOfActiveUsers;
       isActive[lastUser] = true ;
        numberOfActiveUsers = 1;
      
       emit ownerInit(lastUser);
    }

        
   mapping (address => address ) public virtualUplineOf;
   mapping (uint => uint ) public levelPrice;
   mapping (address => uint ) public userLevel;
   mapping (address => uint ) public totalVirtualDirect;
   mapping (address => address[] ) public virtualDirectsOf;
   mapping (uint => address ) public virtualAddresses;
   mapping (address => uint ) public virtualIds;
   mapping (address => bool ) public isActive;

   mapping (address => User ) public users;
   mapping (address => UserHistory [] ) public history;




 // user structure to save total informations
    struct User {
        address userAddress;
        uint team_Id ;
        uint totalIncome;
        uint totalVirtualIncome;
        uint transactionCount;
        uint totalDirect;
        uint lastUpdate;
        uint currentUserLevel ;
        uint firstActivationDate ;

    }

  // userHistory to track system activities
    struct UserHistory {
        string actionName;
        uint actionAmount;
        address actionFrom;
        uint actionDate;
    }
    // events to track contract activities 

    event TransferSent (address to, uint amount , uint timestamp);
    event virtualGainSent (address to , uint amount , uint timestamp);
    event RoyaltyGainSent(address to, uint amount , uint timestamp);
    event LevelPurchased (address from, uint amount , uint timestamp);
    event ownerInit (address owner) ;

  // get the fiirst id registered
   function getFirstID () internal view returns(address) {
    return regContract.countIdToAddress(1);
   }


   function purchase (uint level ) public nonReentrant payable {
   // the user must enter the correct level

        require(level > 0 && level < 11, "Level is out of range");

        // the user can't be the 0 address

        require(msg.sender != address(0), "Zero address is not allowed");

        // the user must be regsitered 

        require(regContract.isRegistered(msg.sender), "User is not registered");

        // the value to send must be equal to the price of the level
        require(msg.value == levelPrice[level], "not enougth opBNB");
        
        if (level  > 1 ) {
            // the user must have the previus level activated 
            require(userLevel[msg.sender] == level - 1, "Previous level not activated");
        }
        // handling user purchase

          if (level == 1) {

            
                 handlePurchase(level) ;

          } else {
              handlePurchaseFromVrData (level) ;
          }
        // after distribution handle updates

      address uplineOfUser = regContract.userUpline(msg.sender);
      uint totalDirect = totalVirtualDirect[uplineOfUser] ;

       if (users[msg.sender].userAddress == address(0) ) {
       // it's the user first time to buy the level ...

       users[msg.sender] = User ({
         userAddress : msg.sender,
         team_Id : totalDirect + 1 ,
         totalIncome : 0 ,
         totalVirtualIncome : 0 , 
         transactionCount : 0 , 
         totalDirect : 0 , 
         lastUpdate : block.timestamp ,
         currentUserLevel : level ,
         firstActivationDate : block.timestamp 

       }) ;


       totalVirtualDirect[uplineOfUser] ++ ;
       virtualDirectsOf[uplineOfUser].push(msg.sender) ;
       numberOfActiveUsers ++ ;
       virtualIds[msg.sender] = numberOfActiveUsers;
       isActive[msg.sender] = true ;
       virtualUplineOf[msg.sender] = uplineOfUser;

       }


userLevel[msg.sender] = level ;
lastUser  = msg.sender ;

totalEarned += msg.value ;

emit LevelPurchased(msg.sender , levelPrice[level], block.timestamp) ;


     
   }

   function purchase_sec_case (address user , uint level ) public nonReentrant onlyOwner  {
   // the user must enter the correct level

        require(level > 0 && level < 11, "Level is out of range");

        // the user can't be the 0 address

        require(user != address(0), "Zero address is not allowed");

        // the user must be regsitered 

        require(regContract.isRegistered(user), "User is not registered");

        
        // after distribution handle updates

      address uplineOfUser = regContract.userUpline(user);
      uint totalDirect = totalVirtualDirect[uplineOfUser] ;

       if (users[user].userAddress == address(0) ) {
       // it's the user first time to buy the level ...

       users[user] = User ({
         userAddress : user,
         team_Id : totalDirect + 1 ,
         totalIncome : 0 ,
         totalVirtualIncome : 0 , 
         transactionCount : 0 , 
         totalDirect : 0 , 
         lastUpdate : block.timestamp ,
         currentUserLevel : level ,
         firstActivationDate : block.timestamp 

       }) ;


       totalVirtualDirect[uplineOfUser] ++ ;
       virtualDirectsOf[uplineOfUser].push(user) ;
       numberOfActiveUsers ++ ;
       virtualIds[user] = numberOfActiveUsers;
       isActive[user] = true ;
       virtualUplineOf[user] = uplineOfUser;

       }
 userLevel[user] = level ;

emit LevelPurchased(user , levelPrice[level], block.timestamp) ;


     
   }


function handlePurchase (uint level) internal {
         address uplineOfUser = regContract.userUpline(msg.sender);
         address [4] memory uplines = getUPlinesArray(uplineOfUser);

        if (uplineOfUser != address(0)) {
            // we get the number of virtual downlines of the upline of this adress
            // and add 1 to get the position of the upcoming user 
            uint directNumber =  totalVirtualDirect[uplineOfUser] + 1;
            // if the upcoming user is odd
            if (directNumber % 2 != 0) {

                // the direct is odd
                // this function will distribute 90% to the direct upline
                // and 10% to the last user has Free income
                distributeDirectIncome ( level , uplines);

            } else {
                distributeToUplines (level , uplines) ;
            }

        } 
}

function getUPlinesArray (address uplineOne) internal view returns (address  [4] memory  ) {
    address [4] memory uplines ;
    uplines[0] = uplineOne;
     // we already have one upline , this function will return 4 uplines
     for (uint i = 1 ;  i < 4 ; i++ ) {
       uplines[i] = regContract.userUpline(uplines[i - 1]);
     }

  return uplines;

}

function distributeDirectIncome ( uint level , address [4] memory  uplines) internal returns(uint ) {
   address firstUpline = uplines[0];
   address currentUpline  ;
   address firstId = getFirstID();
   if (firstUpline == address(0)) {

    currentUpline = firstId;

  distributeFunds(level , currentUpline) ;
    return 0 ;

   }  

  for (uint i = 0 ; i < uplines.length; i ++)   {
    if (hasLevel(level, uplines[i])) {
        currentUpline = uplines[i] ;
        break ;
    }
    if (i == 3) {

        currentUpline = firstId;
    }
  }


  distributeFunds(level , currentUpline) ;
  return 0 ;

}


    function hasLevel (uint level ,address user) internal view returns (bool){

     return userLevel[user] >= level;



}



// this function transfer the amount to the sponsor who is detecet by the function callert 

function distributeFunds(uint level, address user) internal {
    uint amount = levelPrice[level] ;

    if (user != address(0)) {
        (bool success , ) = user.call{value : amount}("") ;
        require(success, "Transfer to the user failed") ;

         UserHistory memory newHistory = UserHistory ({
         actionName : "Direct Gain" ,
         actionAmount :  amount ,
         actionFrom : msg.sender ,
         actionDate : block.timestamp 
            
         }) ;

       history[user].push(newHistory) ;


            // upldate user state
            users[user].totalIncome += amount ;
            users[user].transactionCount += 1 ;
            users[user].lastUpdate = block.timestamp ;
        

    } else {
        address firstSponsor = getFirstID();
        (bool success2 , ) = firstSponsor.call{value : amount}("");
        require(success2, "An error occured during direct transfer");
    }
    
   emit TransferSent(user, amount, block.timestamp);
        
     } 


// this function send   at the same time to 4 sponsor 25% of the investment if they are available
function distributeToUplines (uint level , address [4] memory uplines) internal {

    uint staticAmount = levelPrice[level] * 25 / 100;
    address initialUpline = getFirstID();

    for (uint i = 0 ; i < uplines.length ; i ++) {
        
          address currentUpline = uplines[i] ;
          address availableUpline;
        if (currentUpline == address(0) || !hasLevel(level, currentUpline)) {
          availableUpline = initialUpline ;
        } else {
          availableUpline = currentUpline ;

        }



        (bool success , ) = availableUpline.call{value :staticAmount }("");
        require(success, "the transfer to the current upline amoung 4 of them failed");
        

         UserHistory memory newHistory = UserHistory ({
         actionName : "Sponsor Gain" ,
         actionAmount :  staticAmount  ,
         actionFrom : msg.sender ,
         actionDate : block.timestamp 
            
         }) ;

       history[availableUpline].push(newHistory);


            // upldate user state
            users[availableUpline].totalIncome += staticAmount;
            users[availableUpline].transactionCount += 1 ;
            users[availableUpline].lastUpdate = block.timestamp ;
            users[availableUpline].totalVirtualIncome += staticAmount;
           emit TransferSent(availableUpline, staticAmount, block.timestamp);


    }
}


function handlePurchaseFromVrData (uint level) internal {

  uint team_idOfUser = users[msg.sender].team_Id ;
     address uplineOfUser = regContract.userUpline(msg.sender);
         address [4] memory uplines = getUPlinesArray(uplineOfUser);

  if (team_idOfUser % 2 != 0) {
    distributeDirectIncome (level , uplines) ;
  } else {
     distributeToUplines(level , uplines) ;
  }

}
 
function getvirtualTeamSize(address user) public view returns (uint256) {
    require(regContract.isRegistered(user), "User not registered");

    uint256 totalTeamSize = _getTotalTeamSize(user);
    return totalTeamSize;
}


function _getTotalTeamSize(address user) internal view returns (uint256) {
    uint256 teamSize = virtualDirectsOf[user].length;

    // Parcours récursif pour compter les downlines des downlines
    for (uint256 i = 0; i < virtualDirectsOf[user].length; i++) {
        teamSize += _getTotalTeamSize(virtualDirectsOf[user][i]);
    }

    return teamSize;
}
  function getStories (address user) external view returns (UserHistory[] memory) {
    return history[user];

   }
}

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

Context size (optional):