ETH Price: $2,511.84 (-0.70%)

Transaction Decoder

Block:
8313829 at Aug-09-2019 02:53:37 AM +UTC
Transaction Fee:
0.000090192 ETH $0.23
Gas Used:
30,064 Gas / 3 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x367Ec476...3D334dcDa
1.4686299558 Eth
Nonce: 51
1.4685397638 Eth
Nonce: 52
0.000090192
(Spark Pool)
4,631.451227302220332435 Eth4,631.451317494220332435 Eth0.000090192

Execution Trace

ReserveFund.miningToken( _tokenAmount=19400000000000000000 )
  • Citizen.isCitizen( _user=0x367Ec476C531173382D15A3B811CdCb3D334dcDa ) => ( True )
  • Wallet.getProfitBalance( _investor=0x367Ec476C531173382D15A3B811CdCb3D334dcDa ) => ( 337 )
    File 1 of 3: ReserveFund
    pragma solidity 0.4.25;
    
    contract Auth {
    
      address internal mainAdmin;
      address internal contractAdmin;
    
      event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);
    
      constructor(
        address _mainAdmin,
        address _contractAdmin
      )
      internal
      {
        mainAdmin = _mainAdmin;
        contractAdmin = _contractAdmin;
      }
    
      modifier onlyAdmin() {
        require(isMainAdmin() || isContractAdmin(), "onlyAdmin");
        _;
      }
    
      modifier onlyMainAdmin() {
        require(isMainAdmin(), "onlyMainAdmin");
        _;
      }
    
      modifier onlyContractAdmin() {
        require(isContractAdmin(), "onlyContractAdmin");
        _;
      }
    
      function transferOwnership(address _newOwner) onlyContractAdmin internal {
        require(_newOwner != address(0x0));
        contractAdmin = _newOwner;
        emit OwnershipTransferred(msg.sender, _newOwner);
      }
    
      function isMainAdmin() public view returns (bool) {
        return msg.sender == mainAdmin;
      }
    
      function isContractAdmin() public view returns (bool) {
        return msg.sender == contractAdmin;
      }
    }
    
    library Math {
      function abs(int number) internal pure returns (uint) {
        if (number < 0) {
          return uint(number * -1);
        }
        return uint(number);
      }
    }
    
    library StringUtil {
      struct slice {
        uint _length;
        uint _pointer;
      }
    
      function validateUserName(string memory _username)
      internal
      pure
      returns (bool)
      {
        uint8 len = uint8(bytes(_username).length);
        if ((len < 4) || (len > 18)) return false;
    
        // only contain A-Z 0-9
        for (uint8 i = 0; i < len; i++) {
          if (
            (uint8(bytes(_username)[i]) < 48) ||
            (uint8(bytes(_username)[i]) > 57 && uint8(bytes(_username)[i]) < 65) ||
            (uint8(bytes(_username)[i]) > 90)
          ) return false;
        }
        // First char != '0'
        return uint8(bytes(_username)[0]) != 48;
      }
    }
    
    interface IWallet {
    
      function bonusForAdminWhenUserBuyPackageViaDollar(uint _amount, address _admin) external;
    
      function bonusNewRank(address _investorAddress, uint _currentRank, uint _newRank) external;
    
      function mineToken(address _from, uint _amount) external;
    
      function deposit(address _to, uint _deposited, uint8 _source, uint _sourceAmount) external;
    
      function getInvestorLastDeposited(address _investor) external view returns (uint);
    
      function getUserWallet(address _investor) external view returns (uint, uint[], uint, uint, uint, uint, uint);
    
      function getProfitBalance(address _investor) external view returns (uint);
    
      function increaseETHWithdrew(uint _amount) external;
    
      function validateCanMineToken(uint _tokenAmount, address _from) external view;
    }
    
    interface ICitizen {
    
      function addF1DepositedToInviter(address _invitee, uint _amount) external;
    
      function addNetworkDepositedToInviter(address _inviter, uint _amount, uint _source, uint _sourceAmount) external;
    
      function checkInvestorsInTheSameReferralTree(address _inviter, address _invitee) external view returns (bool);
    
      function getF1Deposited(address _investor) external view returns (uint);
    
      function getId(address _investor) external view returns (uint);
    
      function getInvestorCount() external view returns (uint);
    
      function getInviter(address _investor) external view returns (address);
    
      function getDirectlyInvitee(address _investor) external view returns (address[]);
    
      function getDirectlyInviteeHaveJoinedPackage(address _investor) external view returns (address[]);
    
      function getNetworkDeposited(address _investor) external view returns (uint);
    
      function getRank(address _investor) external view returns (uint);
    
      function getRankBonus(uint _index) external view returns (uint);
    
      function getUserAddresses(uint _index) external view returns (address);
    
      function getSubscribers(address _investor) external view returns (uint);
    
      function increaseInviterF1HaveJoinedPackage(address _invitee) external;
    
      function isCitizen(address _user) view external returns (bool);
    
      function register(address _user, string _userName, address _inviter) external returns (uint);
    
      function showInvestorInfo(address _investorAddress) external view returns (uint, string memory, address, address[], uint, uint, uint, uint);
    }
    
    /**
     * @title ERC20 interface
     * @dev see https://eips.ethereum.org/EIPS/eip-20
     */
    contract IERC20 {
        function transfer(address to, uint256 value) public returns (bool);
    
        function approve(address spender, uint256 value) public returns (bool);
    
        function transferFrom(address from, address to, uint256 value) public returns (bool);
    
        function balanceOf(address who) public view returns (uint256);
    
        function allowance(address owner, address spender) public view returns (uint256);
    
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    contract ReserveFund is Auth {
      using StringUtil for *;
      using Math for int;
    
      enum Lock {
        UNLOCKED,
        PROFIT,
        MINING_TOKEN,
        BOTH
      }
    
      mapping(address => Lock) public lockedAccounts;
      uint private miningDifficulty = 200000; // $200
      uint private transferDifficulty = 1000; // $1
      uint private aiTokenG3; // 1 ETH = aiTokenG3 DAB
      uint public aiTokenG2; // in mili-dollar (1/1000 dollar)
      uint public minJoinPackage = 200000; // $200
      uint public maxJoinPackage = 5000000; // $5k
      uint public currentETHPrice;
      bool public enableJoinPackageViaEther = true;
    
      ICitizen private citizen;
      IWallet private wallet;
      IERC20 public dabToken;
    
      event AccountsLocked(address[] addresses, uint8 lockingType);
      event AITokenG2Set(uint rate);
      event AITokenG3Set(uint rate);
      event ETHPriceSet(uint ethPrice);
      event EnableJoinPackageViaEtherSwitched(bool enabled);
      event EtherPriceUpdated(uint currentETHPrice);
      event MinJoinPackageSet(uint minJoinPackage);
      event MaxJoinPackageSet(uint maxJoinPackage);
      event MiningDifficultySet(uint rate);
      event TransferDifficultySet(uint value);
      event PackageJoinedViaEther(address buyer, address receiver, uint amount);
      event PackageJoinedViaToken(address buyer, address receiver, uint amount);
      event PackageJoinedViaDollar(address buyer, address receiver, uint amount);
      event Registered(uint id, string userName, address userAddress, address inviter);
      event TokenMined(address buyer, uint amount, uint walletAmount);
      event TokenSwapped(address seller, uint amount, uint ethAmount);
    
      constructor (
        address _citizen,
        address _wallet,
        address _mainAdmin,
        uint _currentETHPrice
      )
      Auth(_mainAdmin, msg.sender)
      public
      {
        citizen = ICitizen(_citizen);
        wallet = IWallet(_wallet);
        currentETHPrice = _currentETHPrice;
      }
    
      // ADMINS FUNCTIONS
    
      function setDABankingToken(address _dabToken) onlyAdmin public {
        dabToken = IERC20(_dabToken);
      }
    
      function updateETHPrice(uint _currentETHPrice) onlyAdmin public {
        require(_currentETHPrice > 0, "Must be > 0");
        require(_currentETHPrice != currentETHPrice, "Must be new value");
        currentETHPrice = _currentETHPrice;
        emit ETHPriceSet(currentETHPrice);
      }
    
      function updateContractAdmin(address _newAddress) onlyAdmin public {
        transferOwnership(_newAddress);
      }
    
      function setMinJoinPackage(uint _minJoinPackage) onlyAdmin public {
        require(_minJoinPackage > 0, "Must be > 0");
        require(_minJoinPackage < maxJoinPackage, "Must be < maxJoinPackage");
        require(_minJoinPackage != minJoinPackage, "Must be new value");
        minJoinPackage = _minJoinPackage;
        emit MinJoinPackageSet(minJoinPackage);
      }
    
      function setMaxJoinPackage(uint _maxJoinPackage) onlyAdmin public {
        require(_maxJoinPackage > minJoinPackage, "Must be > minJoinPackage");
        require(_maxJoinPackage != maxJoinPackage, "Must be new value");
        maxJoinPackage = _maxJoinPackage;
        emit MaxJoinPackageSet(maxJoinPackage);
      }
    
      function setEnableJoinPackageViaEther(bool _enableJoinPackageViaEther) onlyAdmin public {
        require(_enableJoinPackageViaEther != enableJoinPackageViaEther, "Must be new value");
        enableJoinPackageViaEther = _enableJoinPackageViaEther;
        emit EnableJoinPackageViaEtherSwitched(enableJoinPackageViaEther);
      }
    
      function aiSetTokenG2(uint _rate) onlyAdmin public {
        require(_rate > 0, "aiTokenG2 must be > 0");
        require(_rate != aiTokenG2, "aiTokenG2 must be new value");
        aiTokenG2 = _rate;
        emit AITokenG2Set(aiTokenG2);
      }
    
      function aiSetTokenG3(uint _rate) onlyAdmin public {
        require(_rate > 0, "aiTokenG3 must be > 0");
        require(_rate != aiTokenG3, "aiTokenG3 must be new value");
        aiTokenG3 = _rate;
        emit AITokenG3Set(aiTokenG3);
      }
    
      function setMiningDifficulty(uint _miningDifficulty) onlyAdmin public {
        require(_miningDifficulty > 0, "miningDifficulty must be > 0");
        require(_miningDifficulty != miningDifficulty, "miningDifficulty must be new value");
        miningDifficulty = _miningDifficulty;
        emit MiningDifficultySet(miningDifficulty);
      }
    
      function setTransferDifficulty(uint _transferDifficulty) onlyAdmin public {
        require(_transferDifficulty > 0, "MinimumBuy must be > 0");
        require(_transferDifficulty != transferDifficulty, "transferDifficulty must be new value");
        transferDifficulty = _transferDifficulty;
        emit TransferDifficultySet(transferDifficulty);
      }
    
      function lockAccounts(address[] _addresses, uint8 _type) onlyAdmin public {
        require(_addresses.length > 0, "Address cannot be empty");
        require(_addresses.length <= 256, "Maximum users per action is 256");
        require(_type >= 0 && _type <= 3, "Type is invalid");
        for (uint8 i = 0; i < _addresses.length; i++) {
          require(_addresses[i] != msg.sender, "You cannot lock yourself");
          lockedAccounts[_addresses[i]] = Lock(_type);
        }
        emit AccountsLocked(_addresses, _type);
      }
    
      // PUBLIC FUNCTIONS
    
      function () public payable {}
    
      function getAITokenG3() view public returns (uint) {
        return aiTokenG3;
      }
    
      function getMiningDifficulty() view public returns (uint) {
        return miningDifficulty;
      }
    
      function getTransferDifficulty() view public returns (uint) {
        return transferDifficulty;
      }
    
      function getLockedStatus(address _investor) view public returns (uint8) {
        return uint8(lockedAccounts[_investor]);
      }
    
      function register(string memory _userName, address _inviter) public {
        require(citizen.isCitizen(_inviter), "Inviter did not registered.");
        require(_inviter != msg.sender, "Cannot referral yourself");
        uint id = citizen.register(msg.sender, _userName, _inviter);
        emit Registered(id, _userName, msg.sender, _inviter);
      }
    
      function showMe() public view returns (uint, string memory, address, address[], uint, uint, uint, uint) {
        return citizen.showInvestorInfo(msg.sender);
      }
    
      function joinPackageViaEther(uint _rate, address _to) payable public {
        require(enableJoinPackageViaEther, "Can not buy via Ether now");
        validateJoinPackage(msg.sender, _to);
        require(_rate > 0, "Rate must be > 0");
        validateAmount(_to, (msg.value * _rate) / (10 ** 18));
        bool rateHigherUnder3Percents = (int(currentETHPrice - _rate).abs() * 100 / _rate) <= uint(3);
        bool rateLowerUnder5Percents = (int(_rate - currentETHPrice).abs() * 100 / currentETHPrice) <= uint(5);
        bool validRate = rateHigherUnder3Percents && rateLowerUnder5Percents;
        require(validRate, "Invalid rate, please check again!");
        doJoinViaEther(msg.sender, _to, msg.value, _rate);
      }
    
      function joinPackageViaDollar(uint _amount, address _to) public {
        validateJoinPackage(msg.sender, _to);
        validateAmount(_to, _amount);
        validateProfitBalance(msg.sender, _amount);
        wallet.deposit(_to, _amount, 2, _amount);
        wallet.bonusForAdminWhenUserBuyPackageViaDollar(_amount / 10, mainAdmin);
        emit PackageJoinedViaDollar(msg.sender, _to, _amount);
      }
    
      function joinPackageViaToken(uint _amount, address _to) public {
        validateJoinPackage(msg.sender, _to);
        validateAmount(_to, _amount);
        uint tokenAmount = (_amount / aiTokenG2) * (10 ** 18);
        require(dabToken.allowance(msg.sender, address(this)) >= tokenAmount, "You must call approve() first");
        uint userOldBalance = dabToken.balanceOf(msg.sender);
        require(userOldBalance >= tokenAmount, "You have not enough tokens");
        require(dabToken.transferFrom(msg.sender, address(this), tokenAmount), "Transfer token failed");
        require(dabToken.transfer(mainAdmin, tokenAmount / 10), "Transfer token to admin failed");
        wallet.deposit(_to, _amount, 1, tokenAmount);
        emit PackageJoinedViaToken(msg.sender, _to, _amount);
      }
    
      function miningToken(uint _tokenAmount) public {
        require(aiTokenG2 > 0, "Invalid aiTokenG2, please contact admin");
        require(citizen.isCitizen(msg.sender), "Please register first");
        validateLockingMiningToken(msg.sender);
        require(_tokenAmount > miningDifficulty, "Amount must be > miningDifficulty");
        uint fiatAmount = (_tokenAmount * aiTokenG2) / (10 ** 18);
        validateProfitBalance(msg.sender, fiatAmount);
        wallet.validateCanMineToken(fiatAmount, msg.sender);
    
        wallet.mineToken(msg.sender, fiatAmount);
        uint userOldBalance = dabToken.balanceOf(msg.sender);
        require(dabToken.transfer(msg.sender, _tokenAmount), "Transfer token to user failed");
        require(dabToken.balanceOf(msg.sender) == userOldBalance + _tokenAmount, "User token changed invalid");
        emit TokenMined(msg.sender, _tokenAmount, fiatAmount);
      }
    
      function swapToken(uint _amount) public {
        require(_amount > 0, "Invalid amount to swap");
        require(dabToken.balanceOf(msg.sender) >= _amount, "You have not enough balance");
        uint etherAmount = getEtherAmountFromToken(_amount);
        require(address(this).balance >= etherAmount, "The contract have not enough balance");
        require(dabToken.allowance(msg.sender, address(this)) >= _amount, "You must call approve() first");
        require(dabToken.transferFrom(msg.sender, address(this), _amount), "Transfer token failed");
        msg.sender.transfer(etherAmount);
        wallet.increaseETHWithdrew(etherAmount);
        emit TokenSwapped(msg.sender, _amount, etherAmount);
      }
    
      function getCurrentEthPrice() public view returns (uint) {
        return currentETHPrice;
      }
    
      // PRIVATE FUNCTIONS
    
      function getEtherAmountFromToken(uint _amount) private view returns (uint) {
        require(aiTokenG3 > 0, "Invalid aiTokenG3, please contact admin");
        return _amount / aiTokenG3;
      }
    
      function doJoinViaEther(address _from, address _to, uint _etherAmountInWei, uint _rate) private {
        uint etherForAdmin = _etherAmountInWei / 10;
        uint packageValue = (_etherAmountInWei * _rate) / (10 ** 18);
        wallet.deposit(_to, packageValue, 0, _etherAmountInWei);
        mainAdmin.transfer(etherForAdmin);
        emit PackageJoinedViaEther(_from, _to, packageValue);
      }
    
      function validateAmount(address _user, uint _packageValue) private view {
        require(_packageValue > 0, "Amount must be > 0");
        require(_packageValue <= maxJoinPackage, "Can not join with amount that greater max join package");
        uint lastBuy = wallet.getInvestorLastDeposited(_user);
        if (lastBuy == 0) {
          require(_packageValue >= minJoinPackage, "Minimum for first join is $200");
        } else {
          require(_packageValue >= lastBuy, "Can not join with amount that lower than your last join");
        }
      }
    
      function validateJoinPackage(address _from, address _to) private view {
        require(citizen.isCitizen(_from), "Please register first");
        require(citizen.isCitizen(_to), "You can only buy for an exists member");
        if (_from != _to) {
          require(citizen.checkInvestorsInTheSameReferralTree(_from, _to), "This user isn't in your referral tree");
        }
        require(currentETHPrice > 0, "Invalid currentETHPrice, please contact admin!");
      }
    
      function validateLockingMiningToken(address _from) private view {
        bool canBuy = lockedAccounts[_from] != Lock.MINING_TOKEN && lockedAccounts[_from] != Lock.BOTH;
        require(canBuy, "Your account get locked from mining token");
      }
    
      function validateProfitBalance(address _user, uint _amount) private view {
        uint profitBalance = wallet.getProfitBalance(_user);
        require(profitBalance >= _amount, "You have not enough balance");
      }
    }

    File 2 of 3: Citizen
    pragma solidity 0.4.25;
    
    /**
     * @title SafeMath
     * @dev Unsigned math operations with safety checks that revert on error.
     */
    library SafeMath {
      /**
       * @dev Multiplies two unsigned integers, reverts on overflow.
       */
      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
          return 0;
        }
    
        uint256 c = a * b;
        require(c / a == b);
    
        return c;
      }
    
      /**
       * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
       */
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    
        return c;
      }
    
      /**
       * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
       */
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;
    
        return c;
      }
    
      /**
       * @dev Adds two unsigned integers, reverts on overflow.
       */
      function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);
    
        return c;
      }
    
      /**
       * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
       * reverts when dividing by zero.
       */
      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
      }
    }
    
    library UnitConverter {
      using SafeMath for uint256;
    
      function stringToBytes24(string memory source)
      internal
      pure
      returns (bytes24 result)
      {
        bytes memory tempEmptyStringTest = bytes(source);
        if (tempEmptyStringTest.length == 0) {
          return 0x0;
        }
    
        assembly {
          result := mload(add(source, 24))
        }
      }
    }
    
    library StringUtil {
      struct slice {
        uint _length;
        uint _pointer;
      }
    
      function validateUserName(string memory _username)
      internal
      pure
      returns (bool)
      {
        uint8 len = uint8(bytes(_username).length);
        if ((len < 4) || (len > 18)) return false;
    
        // only contain A-Z 0-9
        for (uint8 i = 0; i < len; i++) {
          if (
            (uint8(bytes(_username)[i]) < 48) ||
            (uint8(bytes(_username)[i]) > 57 && uint8(bytes(_username)[i]) < 65) ||
            (uint8(bytes(_username)[i]) > 90)
          ) return false;
        }
        // First char != '0'
        return uint8(bytes(_username)[0]) != 48;
      }
    }
    
    contract Auth {
    
      address internal mainAdmin;
      address internal contractAdmin;
    
      event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);
    
      constructor(
        address _mainAdmin,
        address _contractAdmin
      )
      internal
      {
        mainAdmin = _mainAdmin;
        contractAdmin = _contractAdmin;
      }
    
      modifier onlyAdmin() {
        require(isMainAdmin() || isContractAdmin(), "onlyAdmin");
        _;
      }
    
      modifier onlyMainAdmin() {
        require(isMainAdmin(), "onlyMainAdmin");
        _;
      }
    
      modifier onlyContractAdmin() {
        require(isContractAdmin(), "onlyContractAdmin");
        _;
      }
    
      function transferOwnership(address _newOwner) onlyContractAdmin internal {
        require(_newOwner != address(0x0));
        contractAdmin = _newOwner;
        emit OwnershipTransferred(msg.sender, _newOwner);
      }
    
      function isMainAdmin() public view returns (bool) {
        return msg.sender == mainAdmin;
      }
    
      function isContractAdmin() public view returns (bool) {
        return msg.sender == contractAdmin;
      }
    }
    
    library ArrayUtil {
    
      function tooLargestValues(uint[] array) internal pure returns (uint max, uint subMax) {
        require(array.length >= 2, "Invalid array length");
        max = array[0];
        for (uint i = 1; i < array.length; i++) {
          if (array[i] > max) {
            subMax = max;
            max = array[i];
          } else if (array[i] > subMax) {
            subMax = array[i];
          }
        }
      }
    }
    
    interface IWallet {
    
      function bonusForAdminWhenUserBuyPackageViaDollar(uint _amount, address _admin) external;
    
      function bonusNewRank(address _investorAddress, uint _currentRank, uint _newRank) external;
    
      function mineToken(address _from, uint _amount) external;
    
      function deposit(address _to, uint _deposited, uint8 _source, uint _sourceAmount) external;
    
      function getInvestorLastDeposited(address _investor) external view returns (uint);
    
      function getUserWallet(address _investor) external view returns (uint, uint[], uint, uint, uint, uint, uint);
    
      function getProfitBalance(address _investor) external view returns (uint);
    
      function increaseETHWithdrew(uint _amount) external;
    
      function validateCanMineToken(uint _tokenAmount, address _from) external view;
    }
    
    contract Citizen is Auth {
      using ArrayUtil for uint256[];
      using StringUtil for string;
      using UnitConverter for string;
      using SafeMath for uint;
    
      enum Rank {
        UnRanked,
        Star1,
        Star2,
        Star3,
        Star4,
        Star5,
        Star6,
        Star7,
        Star8,
        Star9,
        Star10
      }
    
      enum DepositType {
        Ether,
        Token,
        Dollar
      }
    
      uint[11] public rankCheckPoints = [
        0,
        1000000,
        3000000,
        10000000,
        40000000,
        100000000,
        300000000,
        1000000000,
        2000000000,
        5000000000,
        10000000000
      ];
    
      uint[11] public rankBonuses = [
        0,
        0,
        0,
        0,
        1000000, // $1k
        2000000,
        6000000,
        20000000,
        50000000,
        150000000,
        500000000 // $500k
      ];
    
      struct Investor {
        uint id;
        string userName;
        address inviter;
        address[] directlyInvitee;
        address[] directlyInviteeHaveJoinedPackage;
        uint f1Deposited;
        uint networkDeposited;
        uint networkDepositedViaETH;
        uint networkDepositedViaToken;
        uint networkDepositedViaDollar;
        uint subscribers;
        Rank rank;
      }
    
      address private reserveFundContract;
      IWallet private walletContract;
    
      mapping (address => Investor) private investors;
      mapping (bytes24 => address) private userNameAddresses;
      address[] private userAddresses;
    
      modifier onlyWalletContract() {
        require(msg.sender == address(walletContract), "onlyWalletContract");
        _;
      }
    
      modifier onlyReserveFundContract() {
        require(msg.sender == address(reserveFundContract), "onlyReserveFundContract");
        _;
      }
    
      event RankAchieved(address investor, uint currentRank, uint newRank);
    
      constructor(address _mainAdmin) Auth(_mainAdmin, msg.sender) public {
        setupAdminAccount();
      }
    
      // ONLY-CONTRACT-ADMIN FUNCTIONS
    
      function setWalletContract(address _walletContract) onlyContractAdmin public {
        walletContract = IWallet(_walletContract);
      }
    
      function setDABankContract(address _reserveFundContract) onlyContractAdmin public {
        reserveFundContract = _reserveFundContract;
      }
    
      // ONLY-DABANK-CONTRACT FUNCTIONS
    
      function register(address _user, string memory _userName, address _inviter)
      onlyReserveFundContract
      public
      returns
      (uint)
      {
        require(_userName.validateUserName(), "Invalid username");
        Investor storage investor = investors[_user];
        require(!isCitizen(_user), "Already an citizen");
        bytes24 _userNameAsKey = _userName.stringToBytes24();
        require(userNameAddresses[_userNameAsKey] == address(0x0), "Username already exist");
        userNameAddresses[_userNameAsKey] = _user;
    
        investor.id = userAddresses.length;
        investor.userName = _userName;
        investor.inviter = _inviter;
        investor.rank = Rank.UnRanked;
        increaseInvitersSubscribers(_inviter);
        increaseInviterF1(_inviter, _user);
        userAddresses.push(_user);
        return investor.id;
      }
    
      function showInvestorInfo(address _investorAddress)
      onlyReserveFundContract
      public
      view
      returns (uint, string memory, address, address[], uint, uint, uint, Citizen.Rank)
      {
        Investor storage investor = investors[_investorAddress];
        return (
          investor.id,
          investor.userName,
          investor.inviter,
          investor.directlyInvitee,
          investor.f1Deposited,
          investor.networkDeposited,
          investor.subscribers,
          investor.rank
        );
      }
    
      // ONLY-WALLET-CONTRACT FUNCTIONS
    
      function addF1DepositedToInviter(address _invitee, uint _amount)
      onlyWalletContract
      public
      {
        address inviter = investors[_invitee].inviter;
        investors[inviter].f1Deposited = investors[inviter].f1Deposited.add(_amount);
        assert(investors[inviter].f1Deposited > 0);
      }
    
      // _source: 0-eth 1-token 2-usdt
      function addNetworkDepositedToInviter(address _inviter, uint _amount, uint _source, uint _sourceAmount)
      onlyWalletContract
      public
      {
        require(_inviter != address(0x0), "Invalid inviter address");
        require(_amount >= 0, "Invalid deposit amount");
        require(_source >= 0 && _source <= 2, "Invalid deposit source");
        require(_sourceAmount >= 0, "Invalid source amount");
        investors[_inviter].networkDeposited = investors[_inviter].networkDeposited.add(_amount);
        if (_source == 0) {
          investors[_inviter].networkDepositedViaETH = investors[_inviter].networkDepositedViaETH.add(_sourceAmount);
        } else if (_source == 1) {
          investors[_inviter].networkDepositedViaToken = investors[_inviter].networkDepositedViaToken.add(_sourceAmount);
        } else {
          investors[_inviter].networkDepositedViaDollar = investors[_inviter].networkDepositedViaDollar.add(_sourceAmount);
        }
      }
    
      function increaseInviterF1HaveJoinedPackage(address _invitee)
      public
      onlyWalletContract
      {
        address _inviter = getInviter(_invitee);
        investors[_inviter].directlyInviteeHaveJoinedPackage.push(_invitee);
      }
    
      // PUBLIC FUNCTIONS
    
      function updateRanking() public {
        Investor storage investor = investors[msg.sender];
        Rank currentRank = investor.rank;
        require(investor.directlyInviteeHaveJoinedPackage.length > 2, "Invalid condition to make ranking");
        require(currentRank < Rank.Star10, "Congratulations! You have reached max rank");
        uint investorRevenueToCheckRank = getInvestorRankingRevenue(msg.sender);
        Rank newRank;
        for(uint8 k = uint8(currentRank) + 1; k <= uint8(Rank.Star10); k++) {
          if(investorRevenueToCheckRank >= rankCheckPoints[k]) {
            newRank = getRankFromIndex(k);
          }
        }
        if (newRank > currentRank) {
          walletContract.bonusNewRank(msg.sender, uint(currentRank), uint(newRank));
          investor.rank = newRank;
          emit RankAchieved(msg.sender, uint(currentRank), uint(newRank));
        }
      }
    
      function getInvestorRankingRevenue(address _investor) public view returns (uint) {
        Investor storage investor = investors[_investor];
        if (investor.directlyInviteeHaveJoinedPackage.length <= 2) {
          return 0;
        }
        uint[] memory f1NetworkDeposited = new uint[](investor.directlyInviteeHaveJoinedPackage.length);
        uint sumF1NetworkDeposited = 0;
        for (uint j = 0; j < investor.directlyInviteeHaveJoinedPackage.length; j++) {
          f1NetworkDeposited[j] = investors[investor.directlyInviteeHaveJoinedPackage[j]].networkDeposited;
          sumF1NetworkDeposited = sumF1NetworkDeposited.add(f1NetworkDeposited[j]);
        }
        uint max;
        uint subMax;
        (max, subMax) = f1NetworkDeposited.tooLargestValues();
        return sumF1NetworkDeposited.sub(max).sub(subMax);
      }
    
      function checkInvestorsInTheSameReferralTree(address _inviter, address _invitee)
      public
      view
      returns (bool)
      {
        require(_inviter != _invitee, "They are the same");
        bool inTheSameTreeDownLine = checkInTheSameReferralTree(_inviter, _invitee);
        bool inTheSameTreeUpLine = checkInTheSameReferralTree(_invitee, _inviter);
        return inTheSameTreeDownLine || inTheSameTreeUpLine;
      }
    
      function getInviter(address _investor) public view returns (address) {
        return investors[_investor].inviter;
      }
    
      function getDirectlyInvitee(address _investor) public view returns (address[]) {
        return investors[_investor].directlyInvitee;
      }
    
      function getDirectlyInviteeHaveJoinedPackage(address _investor) public view returns (address[]) {
        return investors[_investor].directlyInviteeHaveJoinedPackage;
      }
    
      function getDepositInfo(address _investor) public view returns (uint, uint, uint, uint, uint) {
        return (
          investors[_investor].f1Deposited,
          investors[_investor].networkDeposited,
          investors[_investor].networkDepositedViaETH,
          investors[_investor].networkDepositedViaToken,
          investors[_investor].networkDepositedViaDollar
        );
      }
    
      function getF1Deposited(address _investor) public view returns (uint) {
        return investors[_investor].f1Deposited;
      }
    
      function getNetworkDeposited(address _investor) public view returns (uint) {
        return investors[_investor].networkDeposited;
      }
    
      function getId(address _investor) public view returns (uint) {
        return investors[_investor].id;
      }
    
      function getUserName(address _investor) public view returns (string) {
        return investors[_investor].userName;
      }
    
      function getRank(address _investor) public view returns (Rank) {
        return investors[_investor].rank;
      }
    
      function getUserAddresses(uint _index) public view returns (address) {
        require(_index >= 0 && _index < userAddresses.length, "Index must be >= 0 or < getInvestorCount()");
        return userAddresses[_index];
      }
    
      function getSubscribers(address _investor) public view returns (uint) {
        return investors[_investor].subscribers;
      }
    
      function isCitizen(address _user) view public returns (bool) {
        Investor storage investor = investors[_user];
        return bytes(investor.userName).length > 0;
      }
    
      function getInvestorCount() public view returns (uint) {
        return userAddresses.length;
      }
    
      function getRankBonus(uint _index) public view returns (uint) {
        return rankBonuses[_index];
      }
    
      // PRIVATE FUNCTIONS
    
      function setupAdminAccount() private {
        string memory _mainAdminUserName = "ADMIN";
        bytes24 _mainAdminUserNameAsKey = _mainAdminUserName.stringToBytes24();
        userNameAddresses[_mainAdminUserNameAsKey] = mainAdmin;
        Investor storage mainAdminInvestor = investors[mainAdmin];
        mainAdminInvestor.id = userAddresses.length;
        mainAdminInvestor.userName = _mainAdminUserName;
        mainAdminInvestor.inviter = 0x0;
        mainAdminInvestor.rank = Rank.UnRanked;
        userAddresses.push(mainAdmin);
      }
    
      function increaseInviterF1(address _inviter, address _invitee) private {
        investors[_inviter].directlyInvitee.push(_invitee);
      }
    
      function checkInTheSameReferralTree(address _from, address _to) private view returns (bool) {
        do {
          Investor storage investor = investors[_from];
          if (investor.inviter == _to) {
            return true;
          }
          _from = investor.inviter;
        } while (investor.inviter != 0x0);
        return false;
      }
    
      function increaseInvitersSubscribers(address _inviter) private {
        do {
          investors[_inviter].subscribers += 1;
          _inviter = investors[_inviter].inviter;
        } while (_inviter != address(0x0));
      }
    
      function getRankFromIndex(uint8 _index) private pure returns (Rank rank) {
        require(_index >= 0 && _index <= 10, "Invalid index");
        if (_index == 1) {
          return Rank.Star1;
        } else if (_index == 2) {
          return Rank.Star2;
        } else if (_index == 3) {
          return Rank.Star3;
        } else if (_index == 4) {
          return Rank.Star4;
        } else if (_index == 5) {
          return Rank.Star5;
        } else if (_index == 6) {
          return Rank.Star6;
        } else if (_index == 7) {
          return Rank.Star7;
        } else if (_index == 8) {
          return Rank.Star8;
        } else if (_index == 9) {
          return Rank.Star9;
        } else if (_index == 10) {
          return Rank.Star10;
        } else {
          return Rank.UnRanked;
        }
      }
    }

    File 3 of 3: Wallet
    pragma solidity 0.4.25;
    
    contract Auth {
    
      address internal mainAdmin;
      address internal contractAdmin;
    
      event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);
    
      constructor(
        address _mainAdmin,
        address _contractAdmin
      )
      internal
      {
        mainAdmin = _mainAdmin;
        contractAdmin = _contractAdmin;
      }
    
      modifier onlyAdmin() {
        require(isMainAdmin() || isContractAdmin(), "onlyAdmin");
        _;
      }
    
      modifier onlyMainAdmin() {
        require(isMainAdmin(), "onlyMainAdmin");
        _;
      }
    
      modifier onlyContractAdmin() {
        require(isContractAdmin(), "onlyContractAdmin");
        _;
      }
    
      function transferOwnership(address _newOwner) onlyContractAdmin internal {
        require(_newOwner != address(0x0));
        contractAdmin = _newOwner;
        emit OwnershipTransferred(msg.sender, _newOwner);
      }
    
      function isMainAdmin() public view returns (bool) {
        return msg.sender == mainAdmin;
      }
    
      function isContractAdmin() public view returns (bool) {
        return msg.sender == contractAdmin;
      }
    }
    
    /**
     * @title SafeMath
     * @dev Unsigned math operations with safety checks that revert on error.
     */
    library SafeMath {
      /**
       * @dev Multiplies two unsigned integers, reverts on overflow.
       */
      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
          return 0;
        }
    
        uint256 c = a * b;
        require(c / a == b);
    
        return c;
      }
    
      /**
       * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
       */
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    
        return c;
      }
    
      /**
       * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
       */
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;
    
        return c;
      }
    
      /**
       * @dev Adds two unsigned integers, reverts on overflow.
       */
      function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);
    
        return c;
      }
    
      /**
       * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
       * reverts when dividing by zero.
       */
      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
      }
    }
    
    interface ICitizen {
    
      function addF1DepositedToInviter(address _invitee, uint _amount) external;
    
      function addNetworkDepositedToInviter(address _inviter, uint _amount, uint _source, uint _sourceAmount) external;
    
      function checkInvestorsInTheSameReferralTree(address _inviter, address _invitee) external view returns (bool);
    
      function getF1Deposited(address _investor) external view returns (uint);
    
      function getId(address _investor) external view returns (uint);
    
      function getInvestorCount() external view returns (uint);
    
      function getInviter(address _investor) external view returns (address);
    
      function getDirectlyInvitee(address _investor) external view returns (address[]);
    
      function getDirectlyInviteeHaveJoinedPackage(address _investor) external view returns (address[]);
    
      function getNetworkDeposited(address _investor) external view returns (uint);
    
      function getRank(address _investor) external view returns (uint);
    
      function getRankBonus(uint _index) external view returns (uint);
    
      function getUserAddresses(uint _index) external view returns (address);
    
      function getSubscribers(address _investor) external view returns (uint);
    
      function increaseInviterF1HaveJoinedPackage(address _invitee) external;
    
      function isCitizen(address _user) view external returns (bool);
    
      function register(address _user, string _userName, address _inviter) external returns (uint);
    
      function showInvestorInfo(address _investorAddress) external view returns (uint, string memory, address, address[], uint, uint, uint, uint);
    }
    
    interface IReserveFund {
    
      function getLockedStatus(address _investor) view external returns (uint8);
    
      function getTransferDifficulty() view external returns (uint);
    }
    
    contract Wallet is Auth {
      using SafeMath for uint;
    
      struct Balance {
        // NOTE: balance is counted in mili-dollar (1/1000 dollar)
        uint totalDeposited; // Treasury package
        uint[] deposited;
        uint profitableBalance; // Green wallet
        uint profitSourceBalance; // Gold wallet
        uint profitBalance; // Mining wallet
        uint totalProfited;
        uint amountToMineToken;
        uint ethWithdrew;
      }
    
      IReserveFund private reserveFundContract;
      ICitizen private citizen;
    
      uint public ethWithdrew;
      uint private profitPaid;
      uint private f11RewardCondition = 200000000; // 200k
    
      mapping (address => Balance) private userWallets;
    
      modifier onlyReserveFundContract() {
        require(msg.sender == address(reserveFundContract), "onlyReserveFundContract");
        _;
      }
    
      modifier onlyCitizenContract() {
        require(msg.sender == address(citizen), "onlyCitizenContract");
        _;
      }
    
      event ProfitBalanceTransferred(address from, address to, uint amount);
      event RankBonusSent(address investor, uint rank, uint amount);
      // source: 0-eth 1-token 2-usdt
      event ProfitSourceBalanceChanged(address investor, int amount, address from, uint8 source);
      event ProfitableBalanceChanged(address investor, int amount, address from, uint8 source);
      // source: 0-profit paid 1-active user
      event ProfitBalanceChanged(address from, address to, int amount, uint8 source);
    
      constructor (address _mainAdmin, address _citizen)
      Auth(_mainAdmin, msg.sender)
      public
      {
        citizen = ICitizen(_citizen);
      }
    
      // ONLY-MAIN-ADMIN-FUNCTIONS
      function getProfitPaid() onlyMainAdmin public view returns(uint) {
        return profitPaid;
      }
    
      // ONLY-CONTRACT-ADMIN FUNCTIONS
    
      function setDABankContract(address _reserveFundContract) onlyContractAdmin public {
        reserveFundContract = IReserveFund(_reserveFundContract);
      }
    
      function makeDailyProfit(address[] _userAddresses) onlyContractAdmin public {
        require(_userAddresses.length > 0, "Invalid input");
        uint investorCount = citizen.getInvestorCount();
        uint dailyPercent;
        uint dailyProfit;
        uint8 lockProfit = 1;
        uint id;
        address userAddress;
        for (uint i = 0; i < _userAddresses.length; i++) {
          id = citizen.getId(_userAddresses[i]);
          require(investorCount > id, "Invalid userId");
          userAddress = _userAddresses[i];
          if (reserveFundContract.getLockedStatus(userAddress) != lockProfit) {
            Balance storage balance = userWallets[userAddress];
            dailyPercent = (balance.totalProfited == 0 || balance.totalProfited < balance.totalDeposited) ? 5 : (balance.totalProfited < 4 * balance.totalDeposited) ? 4 : 3;
            dailyProfit = balance.profitableBalance.mul(dailyPercent).div(1000);
    
            balance.profitableBalance = balance.profitableBalance.sub(dailyProfit);
            balance.profitBalance = balance.profitBalance.add(dailyProfit);
            balance.totalProfited = balance.totalProfited.add(dailyProfit);
            profitPaid = profitPaid.add(dailyProfit);
            emit ProfitBalanceChanged(address(0x0), userAddress, int(dailyProfit), 0);
          }
        }
      }
    
      // ONLY-DABANK-CONTRACT FUNCTIONS
      // _source: 0-eth 1-token 2-usdt
      function deposit(address _to, uint _deposited, uint8 _source, uint _sourceAmount) onlyReserveFundContract public {
        require(_to != address(0x0), "User address can not be empty");
        require(_deposited > 0, "Package value must be > 0");
    
        Balance storage balance = userWallets[_to];
        bool firstDeposit = balance.deposited.length == 0;
        balance.deposited.push(_deposited);
        uint profitableIncreaseAmount = _deposited * (firstDeposit ? 2 : 1);
        uint profitSourceIncreaseAmount = _deposited * 8;
        balance.totalDeposited = balance.totalDeposited.add(_deposited);
        balance.profitableBalance = balance.profitableBalance.add(profitableIncreaseAmount);
        balance.profitSourceBalance = balance.profitSourceBalance.add(_deposited * 8);
        if (_source == 2) {
          if (_to == tx.origin) {
            // self deposit
            balance.profitBalance = balance.profitBalance.sub(_deposited);
          } else {
            // deposit to another
            Balance storage senderBalance = userWallets[tx.origin];
            senderBalance.profitBalance = senderBalance.profitBalance.sub(_deposited);
          }
          emit ProfitBalanceChanged(tx.origin, _to, int(_deposited) * -1, 1);
        }
        citizen.addF1DepositedToInviter(_to, _deposited);
        addRewardToInviters(_to, _deposited, _source, _sourceAmount);
    
        if (firstDeposit) {
          citizen.increaseInviterF1HaveJoinedPackage(_to);
        }
    
        if (profitableIncreaseAmount > 0) {
          emit ProfitableBalanceChanged(_to, int(profitableIncreaseAmount), _to, _source);
          emit ProfitSourceBalanceChanged(_to, int(profitSourceIncreaseAmount), _to, _source);
        }
      }
    
      function bonusForAdminWhenUserBuyPackageViaDollar(uint _amount, address _admin) onlyReserveFundContract public {
        Balance storage adminBalance = userWallets[_admin];
        adminBalance.profitBalance = adminBalance.profitBalance.add(_amount);
      }
    
      function increaseETHWithdrew(uint _amount) onlyReserveFundContract public {
        ethWithdrew = ethWithdrew.add(_amount);
      }
    
      function mineToken(address _from, uint _amount) onlyReserveFundContract public {
        Balance storage userBalance = userWallets[_from];
        userBalance.profitBalance = userBalance.profitBalance.sub(_amount);
        userBalance.amountToMineToken = userBalance.amountToMineToken.add(_amount);
      }
    
      function validateCanMineToken(uint _tokenAmount, address _from) onlyReserveFundContract public view {
        Balance storage userBalance = userWallets[_from];
        require(userBalance.amountToMineToken.add(_tokenAmount) <= 4 * userBalance.totalDeposited, "You can only mine maximum 4x of your total deposited");
      }
    
      // ONLY-CITIZEN-CONTRACT FUNCTIONS
    
      function bonusNewRank(address _investorAddress, uint _currentRank, uint _newRank) onlyCitizenContract public {
        require(_newRank > _currentRank, "Invalid ranks");
        Balance storage balance = userWallets[_investorAddress];
        for (uint8 i = uint8(_currentRank) + 1; i <= uint8(_newRank); i++) {
          uint rankBonusAmount = citizen.getRankBonus(i);
          balance.profitBalance = balance.profitBalance.add(rankBonusAmount);
          if (rankBonusAmount > 0) {
            emit RankBonusSent(_investorAddress, i, rankBonusAmount);
          }
        }
      }
    
      // PUBLIC FUNCTIONS
    
      function getUserWallet(address _investor)
      public
      view
      returns (uint, uint[], uint, uint, uint, uint, uint)
      {
        if (msg.sender != address(reserveFundContract) && msg.sender != contractAdmin && msg.sender != mainAdmin) {
          require(_investor != mainAdmin, "You can not see admin account");
        }
        Balance storage balance = userWallets[_investor];
        return (
          balance.totalDeposited,
          balance.deposited,
          balance.profitableBalance,
          balance.profitSourceBalance,
          balance.profitBalance,
          balance.totalProfited,
          balance.ethWithdrew
        );
      }
    
      function getInvestorLastDeposited(address _investor) public view returns (uint) {
        return userWallets[_investor].deposited.length == 0 ? 0 : userWallets[_investor].deposited[userWallets[_investor].deposited.length - 1];
      }
    
      function transferProfitWallet(uint _amount, address _to) public {
        require(_amount >= reserveFundContract.getTransferDifficulty(), "Amount must be >= minimumTransferProfitBalance");
        Balance storage senderBalance = userWallets[msg.sender];
        require(citizen.isCitizen(msg.sender), "Please register first");
        require(citizen.isCitizen(_to), "You can only transfer to an exists member");
        require(senderBalance.profitBalance >= _amount, "You have not enough balance");
        bool inTheSameTree = citizen.checkInvestorsInTheSameReferralTree(msg.sender, _to);
        require(inTheSameTree, "This user isn't in your referral tree");
        Balance storage receiverBalance = userWallets[_to];
        senderBalance.profitBalance = senderBalance.profitBalance.sub(_amount);
        receiverBalance.profitBalance = receiverBalance.profitBalance.add(_amount);
        emit ProfitBalanceTransferred(msg.sender, _to, _amount);
      }
    
      function getProfitBalance(address _investor) public view returns (uint) {
        return userWallets[_investor].profitBalance;
      }
    
      // PRIVATE FUNCTIONS
    
      function addRewardToInviters(address _invitee, uint _amount, uint8 _source, uint _sourceAmount) private {
        address inviter;
        uint16 referralLevel = 1;
        do {
          inviter = citizen.getInviter(_invitee);
          if (inviter != address(0x0)) {
            citizen.addNetworkDepositedToInviter(inviter, _amount, _source, _sourceAmount);
            checkAddReward(_invitee, inviter, referralLevel, _source, _amount);
            _invitee = inviter;
            referralLevel += 1;
          }
        } while (inviter != address(0x0));
      }
    
      function checkAddReward(address _invitee,address _inviter, uint16 _referralLevel, uint8 _source, uint _amount) private {
        uint f1Deposited = citizen.getF1Deposited(_inviter);
        uint networkDeposited = citizen.getNetworkDeposited(_inviter);
        uint directlyInviteeCount = citizen.getDirectlyInviteeHaveJoinedPackage(_inviter).length;
        uint rank = citizen.getRank(_inviter);
        if (_referralLevel == 1) {
          moveBalanceForInvitingSuccessful(_invitee, _inviter, _referralLevel, _source, _amount);
        } else if (_referralLevel > 1 && _referralLevel < 11) {
          bool condition1 = userWallets[_inviter].deposited.length > 0 ? f1Deposited >= userWallets[_inviter].deposited[0] * 3 : false;
          bool condition2 = directlyInviteeCount >= _referralLevel;
          if (condition1 && condition2) {
            moveBalanceForInvitingSuccessful(_invitee, _inviter, _referralLevel, _source, _amount);
          }
        } else {
          condition1 = userWallets[_inviter].deposited.length > 0 ? f1Deposited >= userWallets[_inviter].deposited[0] * 3: false;
          condition2 = directlyInviteeCount >= 10;
          bool condition3 = networkDeposited >= f11RewardCondition;
          bool condition4 = rank >= 3;
          if (condition1 && condition2 && condition3 && condition4) {
            moveBalanceForInvitingSuccessful(_invitee, _inviter, _referralLevel, _source, _amount);
          }
        }
      }
    
      function moveBalanceForInvitingSuccessful(address _invitee, address _inviter, uint16 _referralLevel, uint8 _source, uint _amount) private {
        uint divider = (_referralLevel == 1) ? 2 : (_referralLevel > 1 && _referralLevel < 11) ? 10 : 20;
        Balance storage balance = userWallets[_inviter];
        uint willMoveAmount = _amount / divider;
        if (balance.profitSourceBalance > willMoveAmount) {
          balance.profitableBalance = balance.profitableBalance.add(willMoveAmount);
          balance.profitSourceBalance = balance.profitSourceBalance.sub(willMoveAmount);
          if (willMoveAmount > 0) {
            emit ProfitableBalanceChanged(_inviter, int(willMoveAmount), _invitee, _source);
            emit ProfitSourceBalanceChanged(_inviter, int(willMoveAmount) * -1, _invitee, _source);
          }
        } else {
          if (balance.profitSourceBalance > 0) {
            emit ProfitableBalanceChanged(_inviter, int(balance.profitSourceBalance), _invitee, _source);
            emit ProfitSourceBalanceChanged(_inviter, int(balance.profitSourceBalance) * -1, _invitee, _source);
          }
          balance.profitableBalance = balance.profitableBalance.add(balance.profitSourceBalance);
          balance.profitSourceBalance = 0;
        }
      }
    }