Transaction Hash:
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 | ||
---|---|---|---|---|---|
0x367Ec476...3D334dcDa |
1.4686299558 Eth
Nonce: 51
|
1.4685397638 Eth
Nonce: 52
| 0.000090192 | ||
0x5A0b54D5...D3E029c4c
Miner
| (Spark Pool) | 4,631.451227302220332435 Eth | 4,631.451317494220332435 Eth | 0.000090192 |
Execution Trace
ReserveFund.miningToken( _tokenAmount=19400000000000000000 )
-
Citizen.isCitizen( _user=0x367Ec476C531173382D15A3B811CdCb3D334dcDa ) => ( True )
-
Wallet.getProfitBalance( _investor=0x367Ec476C531173382D15A3B811CdCb3D334dcDa ) => ( 337 )
miningToken[ReserveFund (ln:364)]
isCitizen[ReserveFund (ln:366)]
validateLockingMiningToken[ReserveFund (ln:367)]
validateProfitBalance[ReserveFund (ln:370)]
getProfitBalance[ReserveFund (ln:437)]
validateCanMineToken[ReserveFund (ln:371)]
mineToken[ReserveFund (ln:373)]
balanceOf[ReserveFund (ln:374)]
transfer[ReserveFund (ln:375)]
balanceOf[ReserveFund (ln:376)]
TokenMined[ReserveFund (ln:377)]
File 1 of 3: ReserveFund
File 2 of 3: Citizen
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; } } 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; } } }