Transaction Hash:
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 | ||
|---|---|---|---|---|---|
| 0x0547cb4b...93013565d | |||||
| 0x1df59626...C0aB66cE3 |
0.868320164595207119 Eth
Nonce: 2635
|
0.867303788595207119 Eth
Nonce: 2636
| 0.001016376 | ||
| 0x37E343F2...C35D636fB | |||||
|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 1,063.56602898360554142 Eth | 1,063.56704535960554142 Eth | 0.001016376 |
Execution Trace
Dispatcher.participateGame( _gameId=10071801, _teamId=23, _userId=267, _sponsorId=0 )
-
BalanceManager.balances( 267 ) => ( 1025809 ) -
BalanceManager.spendUserBalance( _userId=267, _amount=1000 )
participateGame[Dispatcher (ln:336)]
balances[Dispatcher (ln:357)]spendUserBalance[Dispatcher (ln:358)]balances[Dispatcher (ln:363)]spendUserBalance[Dispatcher (ln:364)]GameTeam[Dispatcher (ln:367)]
File 1 of 2: Dispatcher
File 2 of 2: BalanceManager
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;
}
}