ETH Price: $2,092.78 (-1.51%)

Transaction Decoder

Block:
8828360 at Oct-28-2019 02:25:07 PM +UTC
Transaction Fee:
0.000814059 ETH $1.70
Gas Used:
180,902 Gas / 4.5 Gwei

Emitted Events:

163 DABANKING.Transfer( from=[Sender] 0x706ec639892280d36916b119ca11e06c474e0853, to=[Receiver] 0x81e09530176ea2a2ce9ef6e5073679c085bdcece, value=20000000000000000000 )
164 DABANKING.Approval( owner=[Sender] 0x706ec639892280d36916b119ca11e06c474e0853, spender=[Receiver] 0x81e09530176ea2a2ce9ef6e5073679c085bdcece, value=99997880000000000000000000 )
165 DABANKING.Transfer( from=[Receiver] 0x81e09530176ea2a2ce9ef6e5073679c085bdcece, to=0xE81b7e9611936547d18540FbE4e53b104EcC44d0, value=275800000000000000 )
166 DABANKING.Transfer( from=[Receiver] 0x81e09530176ea2a2ce9ef6e5073679c085bdcece, to=Burn, value=315200000000000000 )
167 0xe81b7e9611936547d18540fbe4e53b104ecc44d0.0x3f4bf951e672984be04efab55a20b42d23bebd023eddb58688af3ebc0b4e709b( 0x3f4bf951e672984be04efab55a20b42d23bebd023eddb58688af3ebc0b4e709b, 0x0000000000000000000000000000000000000000000000000000000000000003, 000000000000000000000000706ec639892280d36916b119ca11e06c474e0853, 000000000000000000000000000000000000000000000000000000000000240a, 0000000000000000000000000000000000000000000000000000000000000080, 0000000000000000000000000000000000000000000000000000000000000001, 000000000000000000000000000000000000000000000000000000000000000b, 6c75636b794e756d626572000000000000000000000000000000000000000000 )
168 DABANKING.Transfer( from=[Receiver] 0x81e09530176ea2a2ce9ef6e5073679c085bdcece, to=[Sender] 0x706ec639892280d36916b119ca11e06c474e0853, value=38809000000000000000 )
169 0x81e09530176ea2a2ce9ef6e5073679c085bdcece.0xe260bb0cdf58af341d75a45558e03a7d5ed5b9d61f99704337af3c9b2a0a0e39( 0xe260bb0cdf58af341d75a45558e03a7d5ed5b9d61f99704337af3c9b2a0a0e39, 0x000000000000000000000000706ec639892280d36916b119ca11e06c474e0853, 0x000000000000000000000000000000000000000000000001158e460913d00000, 0x0000000000000000000000000000000000000000000000000000000000000032, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000032, 0000000000000000000000000000000000000000000000000000000000000031, 0000000000000000000000000000000000000000000000010930ce4194f08000, 0000000000000000000000000000000000000000000000021a9543e190228000 )

Account State Difference:

  Address   Before After State Difference Code
(Spark Pool)
72.963540613998622977 Eth72.964354672998622977 Eth0.000814059
0x5E7Ebea6...14f1d0aae
0x706Ec639...C474e0853
0.036115445848035674 Eth
Nonce: 194
0.035301386848035674 Eth
Nonce: 195
0.000814059
0x81E09530...085bDcEcE
0xE81b7e96...04EcC44d0

Execution Trace

0x81e09530176ea2a2ce9ef6e5073679c085bdcece.40e800d8( )
  • DABANKING.allowance( owner=0x706Ec639892280d36916b119CA11E06C474e0853, spender=0x81E09530176eA2A2CE9Ef6e5073679C085bDcEcE ) => ( 99997900000000000000000000 )
  • DABANKING.transferFrom( from=0x706Ec639892280d36916b119CA11E06C474e0853, to=0x81E09530176eA2A2CE9Ef6e5073679C085bDcEcE, value=20000000000000000000 ) => ( True )
  • DABANKING.transfer( to=0xE81b7e9611936547d18540FbE4e53b104EcC44d0, value=275800000000000000 ) => ( True )
  • DABANKING.transfer( to=0xf0342819aD53288c92665658A0f39AFEc4Ba6000, value=315200000000000000 ) => ( True )
  • 0xe81b7e9611936547d18540fbe4e53b104ecc44d0.7d8fe32e( )
  • DABANKING.transfer( to=0x706Ec639892280d36916b119CA11E06C474e0853, value=38809000000000000000 ) => ( True )
  • Citizen.isCitizen( _investor=0xb04bC64dD365597C5b658d809DD0ea2Ae878fBED ) => ( True )
    File 1 of 3: DABANKING
    pragma solidity 0.4.25;
    
    /**
     * @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);
    }
    
    /**
     * @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;
      }
    }
    
    /**
     * @title Standard ERC20 token
     *
     * @dev Implementation of the basic standard token.
     * https://eips.ethereum.org/EIPS/eip-20
     * Originally based on code by FirstBlood:
     * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
     *
     * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
     * all accounts just by listening to said events. Note that this isn't required by the specification, and other
     * compliant implementations may not do it.
     */
    contract ERC20 is IERC20 {
        using SafeMath for uint256;
    
        mapping (address => uint256) internal _balances;
    
        mapping (address => mapping (address => uint256)) private _allowed;
    
        /**
         * @dev Gets the balance of the specified address.
         * @param owner The address to query the balance of.
         * @return A uint256 representing the amount owned by the passed adfunction transferdress.
         */
        function balanceOf(address owner) public view returns (uint256) {
            return _balances[owner];
        }
    
        /**
         * @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 Transfer token to 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) {
            _transfer(msg.sender, 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) {
            _approve(msg.sender, spender, value);
            return true;
        }
    
        /**
         * @dev Transfer tokens from one address to another.
         * Note that while this function emits an Approval event, this is not required as per the specification,
         * and other compliant implementations may not emit the event.
         * @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) {
            _transfer(from, to, value);
            _approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
            return true;
        }
    
        /**
         * @dev Increase the amount of tokens that an owner allowed to a spender.
         * approve should be called when _allowed[msg.sender][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
         * Emits an Approval event.
         * @param spender The address which will spend the funds.
         * @param addedValue The amount of tokens to increase the allowance by.
         */
        function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
            _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
            return true;
        }
    
        /**
         * @dev Decrease the amount of tokens that an owner allowed to a spender.
         * approve should be called when _allowed[msg.sender][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
         * Emits an Approval event.
         * @param spender The address which will spend the funds.
         * @param subtractedValue The amount of tokens to decrease the allowance by.
         */
        function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
            _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
            return true;
        }
    
        /**
         * @dev Transfer token for a specified addresses.
         * @param from The address to transfer from.
         * @param to The address to transfer to.
         * @param value The amount to be transferred.
         */
        function _transfer(address from, address to, uint256 value) internal {
            require(to != address(0));
    
            _balances[from] = _balances[from].sub(value);
            _balances[to] = _balances[to].add(value);
            emit Transfer(from, to, value);
        }
    
        /**
         * @dev Approve an address to spend another addresses' tokens.
         * @param owner The address that owns the tokens.
         * @param spender The address that will spend the tokens.
         * @param value The number of tokens that can be spent.
         */
        function _approve(address owner, address spender, uint256 value) internal {
            require(spender != address(0));
            require(owner != address(0));
    
            _allowed[owner][spender] = value;
            emit Approval(owner, spender, value);
        }
    
    }
    
    contract DABANKING is ERC20 {
      string public constant name = 'DABANKING';
      string public constant symbol = 'DAB';
      uint8 public constant decimals = 18;
      uint256 public constant totalSupply = (200 * 1e6) * (10 ** uint256(decimals));
    
      constructor(address _daBank) public {
        _balances[_daBank] = totalSupply;
        emit Transfer(address(0x0), _daBank, totalSupply);
      }
    }

    File 2 of 3: Burn
    pragma solidity 0.4.25;
    
    contract Burn {
      // This contract does nothing, it was built for burning token purpose
      // Sending any ETH or ERC20 token to this contract will make them stay here forever. Like 0x0 address
    }

    File 3 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, "SafeMath mul error");
    
        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, "SafeMath div error");
        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, "SafeMath sub error");
        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, "SafeMath add error");
    
        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, "SafeMath mod error");
        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;
      address internal profitAdmin;
      address internal ethAdmin;
      address internal LAdmin;
      address internal maxSAdmin;
      address internal backupAdmin;
      address internal commissionAdmin;
    
      event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);
    
      constructor(
        address _mainAdmin,
        address _contractAdmin,
        address _profitAdmin,
        address _ethAdmin,
        address _LAdmin,
        address _maxSAdmin,
        address _backupAdmin,
        address _commissionAdmin
      )
      internal
      {
        mainAdmin = _mainAdmin;
        contractAdmin = _contractAdmin;
        profitAdmin = _profitAdmin;
        ethAdmin = _ethAdmin;
        LAdmin = _LAdmin;
        maxSAdmin = _maxSAdmin;
        backupAdmin = _backupAdmin;
        commissionAdmin = _commissionAdmin;
      }
    
      modifier onlyMainAdmin() {
        require(isMainAdmin(), "onlyMainAdmin");
        _;
      }
    
      modifier onlyContractAdmin() {
        require(isContractAdmin() || isMainAdmin(), "onlyContractAdmin");
        _;
      }
    
      modifier onlyProfitAdmin() {
        require(isProfitAdmin() || isMainAdmin(), "onlyProfitAdmin");
        _;
      }
    
      modifier onlyEthAdmin() {
        require(isEthAdmin() || isMainAdmin(), "onlyEthAdmin");
        _;
      }
    
      modifier onlyLAdmin() {
        require(isLAdmin() || isMainAdmin(), "onlyLAdmin");
        _;
      }
    
      modifier onlyMaxSAdmin() {
        require(isMaxSAdmin() || isMainAdmin(), "onlyMaxSAdmin");
        _;
      }
    
      modifier onlyBackupAdmin() {
        require(isBackupAdmin() || isMainAdmin(), "onlyBackupAdmin");
        _;
      }
    
      modifier onlyBackupAdmin2() {
        require(isBackupAdmin(), "onlyBackupAdmin");
        _;
      }
    
      function isMainAdmin() public view returns (bool) {
        return msg.sender == mainAdmin;
      }
    
      function isContractAdmin() public view returns (bool) {
        return msg.sender == contractAdmin;
      }
    
      function isProfitAdmin() public view returns (bool) {
        return msg.sender == profitAdmin;
      }
    
      function isEthAdmin() public view returns (bool) {
        return msg.sender == ethAdmin;
      }
    
      function isLAdmin() public view returns (bool) {
        return msg.sender == LAdmin;
      }
    
      function isMaxSAdmin() public view returns (bool) {
        return msg.sender == maxSAdmin;
      }
    
      function isBackupAdmin() public view returns (bool) {
        return msg.sender == backupAdmin;
      }
    }
    
    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 bonusForAdminWhenUserJoinPackageViaDollar(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;
    
      function ethWithdrew() external view returns (uint);
    }
    
    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 getUserAddress(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);
    
      function getDepositInfo(address _investor) external view returns (uint, uint, uint, uint, uint);
    
      function rankBonuses(uint _index) external view returns (uint);
    }
    
    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 public reserveFund;
      IWallet public wallet;
      ICitizen public oldCitizen = ICitizen(0xd4051A078383d3fc279603c1273360Ac980CB394);
    
      mapping (address => Investor) private investors;
      mapping (bytes24 => address) private userNameAddresses;
      address[] private userAddresses;
      address private rootAccount = 0xa06Cd23aA37C39095D8CFe3A0fd2654331e63123;
      mapping (address => bool) private ha;
    
      modifier onlyWalletContract() {
        require(msg.sender == address(wallet), "onlyWalletContract");
        _;
      }
    
      modifier onlyReserveFundContract() {
        require(msg.sender == address(reserveFund), "onlyReserveFundContract");
        _;
      }
    
      event RankAchieved(address investor, uint currentRank, uint newRank);
    
      constructor(
        address _mainAdmin,
        address _backupAdmin
      )
      Auth(
        _mainAdmin,
        msg.sender,
        0x0,
        0x0,
        0x0,
        0x0,
        _backupAdmin,
          0x0
      )
      public
      {
        setupRootAccount();
      }
    
      // ONLY-CONTRACT-ADMIN FUNCTIONS
    
      function setW(address _walletContract) onlyContractAdmin public {
        wallet = IWallet(_walletContract);
      }
    
      function setRF(address _reserveFundContract) onlyContractAdmin public {
        reserveFund = _reserveFundContract;
      }
    
      function updateMainAdmin(address _newMainAdmin) onlyBackupAdmin public {
        require(_newMainAdmin != address(0x0), "Invalid address");
        mainAdmin = _newMainAdmin;
      }
    
      function updateContractAdmin(address _newContractAdmin) onlyMainAdmin public {
        require(_newContractAdmin != address(0x0), "Invalid address");
        contractAdmin = _newContractAdmin;
      }
    
      function updateBackupAdmin(address _newBackupAdmin) onlyBackupAdmin2 public {
        require(_newBackupAdmin != address(0x0), "Invalid address");
        backupAdmin = _newBackupAdmin;
      }
    
      function updateHA(address _address, bool _value) onlyMainAdmin public {
        ha[_address] = _value;
      }
    
      function checkHA(address _address) onlyMainAdmin public view returns (bool) {
        return ha[_address];
      }
    
      function syncData(address[] _investors) onlyContractAdmin public {
        for (uint i = 0; i < _investors.length; i++) {
          syncInvestorInfo(_investors[i]);
          syncDepositInfo(_investors[i]);
        }
      }
    
      // ONLY-RESERVE-FUND-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);
      }
    
      function getInviter(address _investor)
      onlyWalletContract
      public
      view
      returns
      (address)
      {
        return investors[_investor].inviter;
      }
    
      // _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) {
          wallet.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) {
        require(msg.sender == address(this) || msg.sender == _investor, "You can't see other investor");
        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 getDirectlyInvitee(address _investor) public view returns (address[]) {
        validateSender(_investor);
        return investors[_investor].directlyInvitee;
      }
    
      function getDirectlyInviteeHaveJoinedPackage(address _investor) public view returns (address[]) {
        validateSender(_investor);
        return investors[_investor].directlyInviteeHaveJoinedPackage;
      }
    
      function getDepositInfo(address _investor) public view returns (uint, uint, uint, uint, uint) {
        validateSender(_investor);
        return (
          investors[_investor].f1Deposited,
          investors[_investor].networkDeposited,
          investors[_investor].networkDepositedViaETH,
          investors[_investor].networkDepositedViaToken,
          investors[_investor].networkDepositedViaDollar
        );
      }
    
      function getF1Deposited(address _investor) public view returns (uint) {
        validateSender(_investor);
        return investors[_investor].f1Deposited;
      }
    
      function getNetworkDeposited(address _investor) public view returns (uint) {
        validateSender(_investor);
        return investors[_investor].networkDeposited;
      }
    
      function getId(address _investor) public view returns (uint) {
        validateSender(_investor);
        return investors[_investor].id;
      }
    
      function getUserName(address _investor) public view returns (string) {
        validateSender(_investor);
        return investors[_investor].userName;
      }
    
      function getRank(address _investor) public view returns (Rank) {
        validateSender(_investor);
        return investors[_investor].rank;
      }
    
      function getUserAddress(uint _index) public view returns (address) {
        require(_index >= 0 && _index < userAddresses.length, "Index must be >= 0 or < getInvestorCount()");
        validateSender(userAddresses[_index]);
        return userAddresses[_index];
      }
    
      function getUserAddressFromUserName(string _userName) public view returns (address) {
        require(_userName.validateUserName(), "Invalid username");
        bytes24 _userNameAsKey = _userName.stringToBytes24();
        validateSender(userNameAddresses[_userNameAsKey]);
        return userNameAddresses[_userNameAsKey];
      }
    
      function getSubscribers(address _investor) public view returns (uint) {
        validateSender(_investor);
        return investors[_investor].subscribers;
      }
    
      function isCitizen(address _investor) view public returns (bool) {
        validateSender(_investor);
        Investor storage investor = investors[_investor];
        return bytes(investor.userName).length > 0;
      }
    
      function getInvestorCount() public view returns (uint) {
        return userAddresses.length;
      }
    
      // PRIVATE FUNCTIONS
    
      function setupRootAccount() private {
        string memory _rootAddressUserName = "ADMIN";
        bytes24 _rootAddressUserNameAsKey = _rootAddressUserName.stringToBytes24();
        userNameAddresses[_rootAddressUserNameAsKey] = rootAccount;
        Investor storage rootInvestor = investors[rootAccount];
        rootInvestor.id = userAddresses.length;
        rootInvestor.userName = _rootAddressUserName;
        rootInvestor.inviter = 0x0;
        rootInvestor.rank = Rank.UnRanked;
        userAddresses.push(rootAccount);
      }
    
      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;
        }
      }
    
      function syncInvestorInfo(address _investor) private {
        uint id;
        string memory userName;
        address inviter;
        address[] memory directlyInvitee;
        uint subscribers;
        (
          id,
          userName,
          inviter,
          directlyInvitee,
          ,,
          subscribers,
        ) = oldCitizen.showInvestorInfo(_investor);
    
        Investor storage investor = investors[_investor];
        investor.id = id;
        investor.userName = userName;
        investor.inviter = inviter;
        investor.directlyInvitee = directlyInvitee;
        investor.directlyInviteeHaveJoinedPackage = oldCitizen.getDirectlyInviteeHaveJoinedPackage(_investor);
        investor.subscribers = subscribers;
        investor.rank = getRankFromIndex(uint8(oldCitizen.getRank(_investor)));
    
        bytes24 userNameAsKey = userName.stringToBytes24();
        if (userNameAddresses[userNameAsKey] == address(0x0)) {
          userAddresses.push(_investor);
          userNameAddresses[userNameAsKey] = _investor;
        }
      }
    
      function syncDepositInfo(address _investor) private {
        uint f1Deposited;
        uint networkDeposited;
        uint networkDepositedViaETH;
        uint networkDepositedViaToken;
        uint networkDepositedViaDollar;
        (
          f1Deposited,
          networkDeposited,
          networkDepositedViaETH,
          networkDepositedViaToken,
          networkDepositedViaDollar
        ) = oldCitizen.getDepositInfo(_investor);
    
        Investor storage investor = investors[_investor];
        investor.f1Deposited = f1Deposited;
        investor.networkDeposited = networkDeposited;
        investor.networkDepositedViaETH = networkDepositedViaETH;
        investor.networkDepositedViaToken = networkDepositedViaToken;
        investor.networkDepositedViaDollar = networkDepositedViaDollar;
      }
    
      function validateSender(address _investor) private view {
        if (msg.sender != _investor && msg.sender != mainAdmin && msg.sender != reserveFund && msg.sender != address(wallet)) {
          require(!ha[_investor]);
        }
      }
    }