ETH Price: $2,039.60 (+2.19%)

Transaction Decoder

Block:
5938739 at Jul-10-2018 11:38:50 AM +UTC
Transaction Fee:
0.001016376 ETH $2.07
Gas Used:
84,698 Gas / 12 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x0547cb4b...93013565d
0x1df59626...C0aB66cE3
0.868320164595207119 Eth
Nonce: 2635
0.867303788595207119 Eth
Nonce: 2636
0.001016376
0x37E343F2...C35D636fB
(Ethermine)
1,063.56602898360554142 Eth1,063.56704535960554142 Eth0.001016376

Execution Trace

Dispatcher.participateGame( _gameId=10071801, _teamId=23, _userId=267, _sponsorId=0 )
  • BalanceManager.balances( 267 ) => ( 1025809 )
  • BalanceManager.spendUserBalance( _userId=267, _amount=1000 )
    File 1 of 2: Dispatcher
    pragma solidity ^0.4.18;
    
    
    contract Ownable {
        address public owner;
        address public newOwnerCandidate;
    
        event OwnershipRequested(address indexed _by, address indexed _to);
        event OwnershipTransferred(address indexed _from, address indexed _to);
    
        constructor() public {
            owner = msg.sender;
        }
    
        modifier onlyOwner() { require(msg.sender == owner); _;}
    
        /// Proposes to transfer control of the contract to a newOwnerCandidate.
        /// @param _newOwnerCandidate address The address to transfer ownership to.
        function transferOwnership(address _newOwnerCandidate) external onlyOwner {
            require(_newOwnerCandidate != address(0));
    
            newOwnerCandidate = _newOwnerCandidate;
    
            emit OwnershipRequested(msg.sender, newOwnerCandidate);
        }
    
        /// Accept ownership transfer. This method needs to be called by the perviously proposed owner.
        function acceptOwnership() external {
            if (msg.sender == newOwnerCandidate) {
                owner = newOwnerCandidate;
                newOwnerCandidate = address(0);
    
                emit OwnershipTransferred(owner, newOwnerCandidate);
            }
        }
    }
    
    
    contract Serverable is Ownable {
        address public server;
    
        modifier onlyServer() { require(msg.sender == server); _;}
    
        function setServerAddress(address _newServerAddress) external onlyOwner {
            server = _newServerAddress;
        }
    }
    
    
    contract ERC223 {
      uint public totalSupply;
      function balanceOf(address who) public view returns (uint);
      
      function name() public view returns (string _name);
      function symbol() public view returns (string _symbol);
      function decimals() public view returns (uint8 _decimals);
      function totalSupply() public view returns (uint256 _supply);
    
      function transfer(address to, uint value) public returns (bool ok);
      function transfer(address to, uint value, bytes data) public returns (bool ok);
      function transfer(address to, uint value, bytes data, string custom_fallback) public returns (bool ok);
      function transferFrom(address _from, address _to, uint _value) public returns (bool ok);
      
      event Transfer(address indexed from, address indexed to, uint value);
    }
    
    contract BalanceManager is Serverable {
        /** player balances **/
        mapping(uint32 => uint64) public balances;
        /** player blocked tokens number **/
        mapping(uint32 => uint64) public blockedBalances;
        /** wallet balances **/
        mapping(address => uint64) public walletBalances;
        /** adress users **/
        mapping(address => uint32) public userIds;
    
        /** Dispatcher contract address **/
        address public dispatcher;
        /** service reward can be withdraw by owners **/
        uint serviceReward;
        /** service reward can be withdraw by owners **/
        uint sentBonuses;
        /** Token used to pay **/
        ERC223 public gameToken;
    
        modifier onlyDispatcher() {require(msg.sender == dispatcher);
            _;}
    
        event Withdraw(address _user, uint64 _amount);
        event Deposit(address _user, uint64 _amount);
    
        constructor(address _gameTokenAddress) public {
            gameToken = ERC223(_gameTokenAddress);
        }
    
        function setDispatcherAddress(address _newDispatcherAddress) external onlyOwner {
            dispatcher = _newDispatcherAddress;
        }
    
        /**
         * Deposits from user
         */
        function tokenFallback(address _from, uint256 _amount, bytes _data) public {
            if (userIds[_from] > 0) {
                balances[userIds[_from]] += uint64(_amount);
            } else {
                walletBalances[_from] += uint64(_amount);
            }
    
            emit Deposit(_from, uint64(_amount));
        }
    
        /**
         * Register user
         */
        function registerUserWallet(address _user, uint32 _id) external onlyServer {
            require(userIds[_user] == 0);
            require(_user != owner);
    
            userIds[_user] = _id;
            if (walletBalances[_user] > 0) {
                balances[_id] += walletBalances[_user];
                walletBalances[_user] = 0;
            }
        }
    
        /**
         * Deposits tokens in game to some user
         */
        function sendTo(address _user, uint64 _amount) external {
            require(walletBalances[msg.sender] >= _amount);
            walletBalances[msg.sender] -= _amount;
            if (userIds[_user] > 0) {
                balances[userIds[_user]] += _amount;
            } else {
                walletBalances[_user] += _amount;
            }
            emit Deposit(_user, _amount);
        }
    
        /**
         * User can withdraw tokens manually in any time
         */
        function withdraw(uint64 _amount) external {
            uint32 userId = userIds[msg.sender];
            if (userId > 0) {
                require(balances[userId] - blockedBalances[userId] >= _amount);
                if (gameToken.transfer(msg.sender, _amount)) {
                    balances[userId] -= _amount;
                    emit Withdraw(msg.sender, _amount);
                }
            } else {
                require(walletBalances[msg.sender] >= _amount);
                if (gameToken.transfer(msg.sender, _amount)) {
                    walletBalances[msg.sender] -= _amount;
                    emit Withdraw(msg.sender, _amount);
                }
            }
        }
    
        /**
         * Server can withdraw tokens to user
         */
        function systemWithdraw(address _user, uint64 _amount) external onlyServer {
            uint32 userId = userIds[_user];
            require(balances[userId] - blockedBalances[userId] >= _amount);
    
            if (gameToken.transfer(_user, _amount)) {
                balances[userId] -= _amount;
                emit Withdraw(_user, _amount);
            }
        }
    
        /**
         * Dispatcher can change user balance
         */
        function addUserBalance(uint32 _userId, uint64 _amount) external onlyDispatcher {
            balances[_userId] += _amount;
        }
    
        /**
         * Dispatcher can change user balance
         */
        function spendUserBalance(uint32 _userId, uint64 _amount) external onlyDispatcher {
            require(balances[_userId] >= _amount);
            balances[_userId] -= _amount;
            if (blockedBalances[_userId] > 0) {
                if (blockedBalances[_userId] <= _amount)
                    blockedBalances[_userId] = 0;
                else
                    blockedBalances[_userId] -= _amount;
            }
        }
    
        /**
         * Server can add bonuses to users, they will take from owner balance
         */
        function addBonus(uint32[] _userIds, uint64[] _amounts) external onlyServer {
            require(_userIds.length == _amounts.length);
    
            uint64 sum = 0;
            for (uint32 i = 0; i < _amounts.length; i++)
                sum += _amounts[i];
    
            require(walletBalances[owner] >= sum);
            for (i = 0; i < _userIds.length; i++) {
                balances[_userIds[i]] += _amounts[i];
                blockedBalances[_userIds[i]] += _amounts[i];
            }
    
            sentBonuses += sum;
            walletBalances[owner] -= sum;
        }
    
        /**
         * Dispatcher can change user balance
         */
        function addServiceReward(uint _amount) external onlyDispatcher {
            serviceReward += _amount;
        }
    
        /**
         * Owner withdraw service fee tokens 
         */
        function serviceFeeWithdraw() external onlyOwner {
            require(serviceReward > 0);
            if (gameToken.transfer(msg.sender, serviceReward))
                serviceReward = 0;
        }
    
        function viewSentBonuses() public view returns (uint) {
            require(msg.sender == owner || msg.sender == server);
            return sentBonuses;
        }
    
        function viewServiceReward() public view returns (uint) {
            require(msg.sender == owner || msg.sender == server);
            return serviceReward;
        }
    }
    
    
    contract BrokerManager is Ownable {
    
    	struct InvestTerm {
    		uint64 amount;
    		uint16 userFee;
    	}
    	/** server address **/
    	address public server;
    	/** invesor fees **/
    	mapping (uint32 => mapping (uint32 => InvestTerm)) public investTerms;
    
    	modifier onlyServer() {require(msg.sender == server); _;}
    
    	function setServerAddress(address _newServerAddress) external onlyOwner {
    		server = _newServerAddress;
    	}
    
    	/**
         * Create investition 
         */
    	function invest(uint32 _playerId, uint32 _investorId, uint64 _amount, uint16 _userFee) external onlyServer {
    		require(_amount > 0 && _userFee > 0);
    		investTerms[_investorId][_playerId] = InvestTerm(_amount, _userFee);
    	}
    
    	/**
         * Delete investition 
         */
    	function deleteInvest(uint32 _playerId, uint32 _investorId) external onlyServer {
    		delete investTerms[_investorId][_playerId];
    	}
    }
    
    
    contract Dispatcher is BrokerManager {
    
        enum GameState {Initialized, Started, Finished, Cancelled}
    
        struct GameTeam {
            uint32 userId;
            uint32 sponsorId;
            uint64 prizeSum;
            uint16 userFee;
        }
    
        struct Game {
            GameState state;
            uint64 entryFee;
            uint32 serviceFee;
            uint32 registrationDueDate;
    
            bytes32 teamsHash;
            bytes32 statsHash;
    
            uint32 teamsNumber;
            uint64 awardSent;
        }
    
        /** balance manager **/
        BalanceManager public balanceManager;
        /** player teams **/
        mapping(uint32 => mapping(uint48 => GameTeam)) public teams;
        /** games **/
        mapping(uint32 => Game) public games;
    
        constructor(address _balanceManagerAddress) public {
            balanceManager = BalanceManager(_balanceManagerAddress);
        }
    
        /**
         * Create new game
         */
        function createGame(
            uint32 _gameId,
            uint64 _entryFee,
            uint32 _serviceFee,
            uint32 _registrationDueDate
        )
        external
        onlyServer
        {
            require(
                games[_gameId].entryFee == 0
                && _gameId > 0
                && _entryFee > 0
                && _registrationDueDate > 0
            );
            games[_gameId] = Game(GameState.Initialized, _entryFee, _serviceFee, _registrationDueDate, 0x0, 0x0, 0, 0);
        }
    
        /**
         * Participate game
         */
        function participateGame(
            uint32 _gameId,
            uint32 _teamId,
            uint32 _userId,
            uint32 _sponsorId
        )
        external
        onlyServer
        {
            Game storage game = games[_gameId];
            require(
                _gameId > 0
                && game.state == GameState.Initialized
                && _teamId > 0
                && _userId > 0
                && teams[_gameId][_teamId].userId == 0
                && game.registrationDueDate > uint32(now)
            );
    
            uint16 userFee = 0;
            if (_sponsorId > 0) {
                require(balanceManager.balances(_sponsorId) >= game.entryFee && investTerms[_sponsorId][_userId].amount > game.entryFee);
                balanceManager.spendUserBalance(_sponsorId, game.entryFee);
                investTerms[_sponsorId][_userId].amount -= game.entryFee;
                userFee = investTerms[_sponsorId][_userId].userFee;
            }
            else {
                require(balanceManager.balances(_userId) >= game.entryFee);
                balanceManager.spendUserBalance(_userId, game.entryFee);
            }
    
            teams[_gameId][_teamId] = GameTeam(_userId, _sponsorId, 0, userFee);
            game.teamsNumber++;
        }
    
        /**
         * Stop participate game, store teams hash
         */
        function startGame(uint32 _gameId, bytes32 _hash) external onlyServer {
            Game storage game = games[_gameId];
            require(
                game.state == GameState.Initialized
                && _gameId > 0
            && _hash != 0x0
            );
    
            game.teamsHash = _hash;
            game.state = GameState.Started;
        }
    
        /**
         * Cancel game
         */
        function cancelGame(uint32 _gameId) external onlyServer {
            Game storage game = games[_gameId];
            require(
                _gameId > 0
                && game.state < GameState.Finished
            );
            game.state = GameState.Cancelled;
        }
    
        /**
         * Finish game, store stats hash
         */
        function finishGame(uint32 _gameId, bytes32 _hash) external onlyServer {
            Game storage game = games[_gameId];
            require(
                _gameId > 0
                && game.state < GameState.Finished
            && _hash != 0x0
            );
            game.statsHash = _hash;
            game.state = GameState.Finished;
        }
    
        /**
         * Reward winners
         */
        function winners(uint32 _gameId, uint32[] _teamIds, uint64[] _teamPrizes) external onlyServer {
            Game storage game = games[_gameId];
            require(game.state == GameState.Finished);
    
            uint64 sumPrize = 0;
            for (uint32 i = 0; i < _teamPrizes.length; i++)
                sumPrize += _teamPrizes[i];
    
            require(uint(sumPrize + game.awardSent) <= uint(game.entryFee * game.teamsNumber));
    
            for (i = 0; i < _teamIds.length; i++) {
                uint32 teamId = _teamIds[i];
                GameTeam storage team = teams[_gameId][teamId];
                uint32 userId = team.userId;
    
                if (team.prizeSum == 0) {
                    if (team.sponsorId > 0) {
                        uint64 userFee = team.userFee * _teamPrizes[i] / 100;
                        balanceManager.addUserBalance(team.sponsorId, userFee);
                        balanceManager.addUserBalance(userId, _teamPrizes[i] - userFee);
                        team.prizeSum = _teamPrizes[i];
                    } else {
                        balanceManager.addUserBalance(userId, _teamPrizes[i]);
                        team.prizeSum = _teamPrizes[i];
                    }
                }
            }
        }
    
        /**
         * Refund money for cancelled game
         */
        function refundCancelledGame(uint32 _gameId, uint32[] _teamIds) external onlyServer {
            Game storage game = games[_gameId];
            require(game.state == GameState.Cancelled);
    
            for (uint32 i = 0; i < _teamIds.length; i++) {
                uint32 teamId = _teamIds[i];
                GameTeam storage team = teams[_gameId][teamId];
    
                require(teams[_gameId][teamId].prizeSum == 0);
    
                if (team.prizeSum == 0) {
                    if (team.sponsorId > 0) {
                        balanceManager.addUserBalance(team.sponsorId, game.entryFee);
                    } else {
                        balanceManager.addUserBalance(team.userId, game.entryFee);
                    }
                    team.prizeSum = game.entryFee;
                }
            }
        }
    }

    File 2 of 2: BalanceManager
    pragma solidity ^0.4.18;
    
     contract ERC223 {
      uint public totalSupply;
      function balanceOf(address who) public view returns (uint);
      
      function name() public view returns (string _name);
      function symbol() public view returns (string _symbol);
      function decimals() public view returns (uint8 _decimals);
      function totalSupply() public view returns (uint256 _supply);
    
      function transfer(address to, uint value) public returns (bool ok);
      function transfer(address to, uint value, bytes data) public returns (bool ok);
      function transfer(address to, uint value, bytes data, string custom_fallback) public returns (bool ok);
      function transferFrom(address _from, address _to, uint _value) public returns (bool ok);
      
      event Transfer(address indexed from, address indexed to, uint value);
    }
    
    
    contract Ownable {
        address public owner;
        address public newOwnerCandidate;
    
        event OwnershipRequested(address indexed _by, address indexed _to);
        event OwnershipTransferred(address indexed _from, address indexed _to);
    
        constructor() public {
            owner = msg.sender;
        }
    
        modifier onlyOwner() { require(msg.sender == owner); _;}
    
        /// Proposes to transfer control of the contract to a newOwnerCandidate.
        /// @param _newOwnerCandidate address The address to transfer ownership to.
        function transferOwnership(address _newOwnerCandidate) external onlyOwner {
            require(_newOwnerCandidate != address(0));
    
            newOwnerCandidate = _newOwnerCandidate;
    
            emit OwnershipRequested(msg.sender, newOwnerCandidate);
        }
    
        /// Accept ownership transfer. This method needs to be called by the perviously proposed owner.
        function acceptOwnership() external {
            if (msg.sender == newOwnerCandidate) {
                owner = newOwnerCandidate;
                newOwnerCandidate = address(0);
    
                emit OwnershipTransferred(owner, newOwnerCandidate);
            }
        }
    }
    
    
    contract Serverable is Ownable {
        address public server;
    
        modifier onlyServer() { require(msg.sender == server); _;}
    
        function setServerAddress(address _newServerAddress) external onlyOwner {
            server = _newServerAddress;
        }
    }
    
    
    contract BalanceManager is Serverable {
        /** player balances **/
        mapping(uint32 => uint64) public balances;
        /** player blocked tokens number **/
        mapping(uint32 => uint64) public blockedBalances;
        /** wallet balances **/
        mapping(address => uint64) public walletBalances;
        /** adress users **/
        mapping(address => uint32) public userIds;
    
        /** Dispatcher contract address **/
        address public dispatcher;
        /** service reward can be withdraw by owners **/
        uint serviceReward;
        /** service reward can be withdraw by owners **/
        uint sentBonuses;
        /** Token used to pay **/
        ERC223 public gameToken;
    
        modifier onlyDispatcher() {require(msg.sender == dispatcher);
            _;}
    
        event Withdraw(address _user, uint64 _amount);
        event Deposit(address _user, uint64 _amount);
    
        constructor(address _gameTokenAddress) public {
            gameToken = ERC223(_gameTokenAddress);
        }
    
        function setDispatcherAddress(address _newDispatcherAddress) external onlyOwner {
            dispatcher = _newDispatcherAddress;
        }
    
        /**
         * Deposits from user
         */
        function tokenFallback(address _from, uint256 _amount, bytes _data) public {
            if (userIds[_from] > 0) {
                balances[userIds[_from]] += uint64(_amount);
            } else {
                walletBalances[_from] += uint64(_amount);
            }
    
            emit Deposit(_from, uint64(_amount));
        }
    
        /**
         * Register user
         */
        function registerUserWallet(address _user, uint32 _id) external onlyServer {
            require(userIds[_user] == 0);
            require(_user != owner);
    
            userIds[_user] = _id;
            if (walletBalances[_user] > 0) {
                balances[_id] += walletBalances[_user];
                walletBalances[_user] = 0;
            }
        }
    
        /**
         * Deposits tokens in game to some user
         */
        function sendTo(address _user, uint64 _amount) external {
            require(walletBalances[msg.sender] >= _amount);
            walletBalances[msg.sender] -= _amount;
            if (userIds[_user] > 0) {
                balances[userIds[_user]] += _amount;
            } else {
                walletBalances[_user] += _amount;
            }
            emit Deposit(_user, _amount);
        }
    
        /**
         * User can withdraw tokens manually in any time
         */
        function withdraw(uint64 _amount) external {
            uint32 userId = userIds[msg.sender];
            if (userId > 0) {
                require(balances[userId] - blockedBalances[userId] >= _amount);
                if (gameToken.transfer(msg.sender, _amount)) {
                    balances[userId] -= _amount;
                    emit Withdraw(msg.sender, _amount);
                }
            } else {
                require(walletBalances[msg.sender] >= _amount);
                if (gameToken.transfer(msg.sender, _amount)) {
                    walletBalances[msg.sender] -= _amount;
                    emit Withdraw(msg.sender, _amount);
                }
            }
        }
    
        /**
         * Server can withdraw tokens to user
         */
        function systemWithdraw(address _user, uint64 _amount) external onlyServer {
            uint32 userId = userIds[_user];
            require(balances[userId] - blockedBalances[userId] >= _amount);
    
            if (gameToken.transfer(_user, _amount)) {
                balances[userId] -= _amount;
                emit Withdraw(_user, _amount);
            }
        }
    
        /**
         * Dispatcher can change user balance
         */
        function addUserBalance(uint32 _userId, uint64 _amount) external onlyDispatcher {
            balances[_userId] += _amount;
        }
    
        /**
         * Dispatcher can change user balance
         */
        function spendUserBalance(uint32 _userId, uint64 _amount) external onlyDispatcher {
            require(balances[_userId] >= _amount);
            balances[_userId] -= _amount;
            if (blockedBalances[_userId] > 0) {
                if (blockedBalances[_userId] <= _amount)
                    blockedBalances[_userId] = 0;
                else
                    blockedBalances[_userId] -= _amount;
            }
        }
    
        /**
         * Server can add bonuses to users, they will take from owner balance
         */
        function addBonus(uint32[] _userIds, uint64[] _amounts) external onlyServer {
            require(_userIds.length == _amounts.length);
    
            uint64 sum = 0;
            for (uint32 i = 0; i < _amounts.length; i++)
                sum += _amounts[i];
    
            require(walletBalances[owner] >= sum);
            for (i = 0; i < _userIds.length; i++) {
                balances[_userIds[i]] += _amounts[i];
                blockedBalances[_userIds[i]] += _amounts[i];
            }
    
            sentBonuses += sum;
            walletBalances[owner] -= sum;
        }
    
        /**
         * Dispatcher can change user balance
         */
        function addServiceReward(uint _amount) external onlyDispatcher {
            serviceReward += _amount;
        }
    
        /**
         * Owner withdraw service fee tokens 
         */
        function serviceFeeWithdraw() external onlyOwner {
            require(serviceReward > 0);
            if (gameToken.transfer(msg.sender, serviceReward))
                serviceReward = 0;
        }
    
        function viewSentBonuses() public view returns (uint) {
            require(msg.sender == owner || msg.sender == server);
            return sentBonuses;
        }
    
        function viewServiceReward() public view returns (uint) {
            require(msg.sender == owner || msg.sender == server);
            return serviceReward;
        }
    }