Transaction Hash:
Block:
6103598 at Aug-07-2018 08:40:18 AM +UTC
Transaction Fee:
0.000183198 ETH
$0.38
Gas Used:
30,533 Gas / 6 Gwei
Emitted Events:
| 77 |
MVLToken.Transfer( from=[Sender] 0xea1dac22edf302a40258005d8ed5baebafc8f545, to=[Receiver] Exchange, value=12000000000000000000000 )
|
| 78 |
Exchange.Deposit( token=MVLToken, user=[Sender] 0xea1dac22edf302a40258005d8ed5baebafc8f545, amount=12000000000000000000000, balance=24500000000000000000000 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x2a0c0DBE...44050c208 | (IDEX) | ||||
| 0xA849EaaE...B6b18Dc71 | |||||
| 0xEA1DAc22...BAFC8F545 |
0.041059624 Eth
Nonce: 3
|
0.040876426 Eth
Nonce: 4
| 0.000183198 | ||
|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 613.850046130079787471 Eth | 613.850229328079787471 Eth | 0.000183198 |
Execution Trace
Exchange.depositToken( token=0xA849EaaE994fb86Afa73382e9Bd88c2B6b18Dc71, amount=12000000000000000000000 )
-
MVLToken.transferFrom( _from=0xEA1DAc22EDf302A40258005d8eD5baEBAFC8F545, _to=0x2a0c0DBEcC7E4D658f48E01e3fA353F44050c208, _value=12000000000000000000000 ) => ( success=True )
depositToken[Exchange (ln:97)]
safeAdd[Exchange (ln:98)]transferFrom[Exchange (ln:100)]Deposit[Exchange (ln:101)]
File 1 of 2: Exchange
File 2 of 2: MVLToken
pragma solidity ^0.4.16;
contract Token {
bytes32 public standard;
bytes32 public name;
bytes32 public symbol;
uint256 public totalSupply;
uint8 public decimals;
bool public allowTransactions;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
function transfer(address _to, uint256 _value) returns (bool success);
function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success);
function approve(address _spender, uint256 _value) returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
}
contract Exchange {
function assert(bool assertion) {
if (!assertion) throw;
}
function safeMul(uint a, uint b) returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeSub(uint a, uint b) returns (uint) {
assert(b <= a);
return a - b;
}
function safeAdd(uint a, uint b) returns (uint) {
uint c = a + b;
assert(c>=a && c>=b);
return c;
}
address public owner;
mapping (address => uint256) public invalidOrder;
event SetOwner(address indexed previousOwner, address indexed newOwner);
modifier onlyOwner {
assert(msg.sender == owner);
_;
}
function setOwner(address newOwner) onlyOwner {
SetOwner(owner, newOwner);
owner = newOwner;
}
function getOwner() returns (address out) {
return owner;
}
function invalidateOrdersBefore(address user, uint256 nonce) onlyAdmin {
if (nonce < invalidOrder[user]) throw;
invalidOrder[user] = nonce;
}
mapping (address => mapping (address => uint256)) public tokens; //mapping of token addresses to mapping of account balances
mapping (address => bool) public admins;
mapping (address => uint256) public lastActiveTransaction;
mapping (bytes32 => uint256) public orderFills;
address public feeAccount;
uint256 public inactivityReleasePeriod;
mapping (bytes32 => bool) public traded;
mapping (bytes32 => bool) public withdrawn;
event Order(address tokenBuy, uint256 amountBuy, address tokenSell, uint256 amountSell, uint256 expires, uint256 nonce, address user, uint8 v, bytes32 r, bytes32 s);
event Cancel(address tokenBuy, uint256 amountBuy, address tokenSell, uint256 amountSell, uint256 expires, uint256 nonce, address user, uint8 v, bytes32 r, bytes32 s);
event Trade(address tokenBuy, uint256 amountBuy, address tokenSell, uint256 amountSell, address get, address give);
event Deposit(address token, address user, uint256 amount, uint256 balance);
event Withdraw(address token, address user, uint256 amount, uint256 balance);
function setInactivityReleasePeriod(uint256 expiry) onlyAdmin returns (bool success) {
if (expiry > 1000000) throw;
inactivityReleasePeriod = expiry;
return true;
}
function Exchange(address feeAccount_) {
owner = msg.sender;
feeAccount = feeAccount_;
inactivityReleasePeriod = 100000;
}
function setAdmin(address admin, bool isAdmin) onlyOwner {
admins[admin] = isAdmin;
}
modifier onlyAdmin {
if (msg.sender != owner && !admins[msg.sender]) throw;
_;
}
function() external {
throw;
}
function depositToken(address token, uint256 amount) {
tokens[token][msg.sender] = safeAdd(tokens[token][msg.sender], amount);
lastActiveTransaction[msg.sender] = block.number;
if (!Token(token).transferFrom(msg.sender, this, amount)) throw;
Deposit(token, msg.sender, amount, tokens[token][msg.sender]);
}
function deposit() payable {
tokens[address(0)][msg.sender] = safeAdd(tokens[address(0)][msg.sender], msg.value);
lastActiveTransaction[msg.sender] = block.number;
Deposit(address(0), msg.sender, msg.value, tokens[address(0)][msg.sender]);
}
function withdraw(address token, uint256 amount) returns (bool success) {
if (safeSub(block.number, lastActiveTransaction[msg.sender]) < inactivityReleasePeriod) throw;
if (tokens[token][msg.sender] < amount) throw;
tokens[token][msg.sender] = safeSub(tokens[token][msg.sender], amount);
if (token == address(0)) {
if (!msg.sender.send(amount)) throw;
} else {
if (!Token(token).transfer(msg.sender, amount)) throw;
}
Withdraw(token, msg.sender, amount, tokens[token][msg.sender]);
}
function adminWithdraw(address token, uint256 amount, address user, uint256 nonce, uint8 v, bytes32 r, bytes32 s, uint256 feeWithdrawal) onlyAdmin returns (bool success) {
bytes32 hash = keccak256(this, token, amount, user, nonce);
if (withdrawn[hash]) throw;
withdrawn[hash] = true;
if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", hash), v, r, s) != user) throw;
if (feeWithdrawal > 50 finney) feeWithdrawal = 50 finney;
if (tokens[token][user] < amount) throw;
tokens[token][user] = safeSub(tokens[token][user], amount);
tokens[token][feeAccount] = safeAdd(tokens[token][feeAccount], safeMul(feeWithdrawal, amount) / 1 ether);
amount = safeMul((1 ether - feeWithdrawal), amount) / 1 ether;
if (token == address(0)) {
if (!user.send(amount)) throw;
} else {
if (!Token(token).transfer(user, amount)) throw;
}
lastActiveTransaction[user] = block.number;
Withdraw(token, user, amount, tokens[token][user]);
}
function balanceOf(address token, address user) constant returns (uint256) {
return tokens[token][user];
}
function trade(uint256[8] tradeValues, address[4] tradeAddresses, uint8[2] v, bytes32[4] rs) onlyAdmin returns (bool success) {
/* amount is in amountBuy terms */
/* tradeValues
[0] amountBuy
[1] amountSell
[2] expires
[3] nonce
[4] amount
[5] tradeNonce
[6] feeMake
[7] feeTake
tradeAddressses
[0] tokenBuy
[1] tokenSell
[2] maker
[3] taker
*/
if (invalidOrder[tradeAddresses[2]] > tradeValues[3]) throw;
bytes32 orderHash = keccak256(this, tradeAddresses[0], tradeValues[0], tradeAddresses[1], tradeValues[1], tradeValues[2], tradeValues[3], tradeAddresses[2]);
if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", orderHash), v[0], rs[0], rs[1]) != tradeAddresses[2]) throw;
bytes32 tradeHash = keccak256(orderHash, tradeValues[4], tradeAddresses[3], tradeValues[5]);
if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", tradeHash), v[1], rs[2], rs[3]) != tradeAddresses[3]) throw;
if (traded[tradeHash]) throw;
traded[tradeHash] = true;
if (tradeValues[6] > 100 finney) tradeValues[6] = 100 finney;
if (tradeValues[7] > 100 finney) tradeValues[7] = 100 finney;
if (safeAdd(orderFills[orderHash], tradeValues[4]) > tradeValues[0]) throw;
if (tokens[tradeAddresses[0]][tradeAddresses[3]] < tradeValues[4]) throw;
if (tokens[tradeAddresses[1]][tradeAddresses[2]] < (safeMul(tradeValues[1], tradeValues[4]) / tradeValues[0])) throw;
tokens[tradeAddresses[0]][tradeAddresses[3]] = safeSub(tokens[tradeAddresses[0]][tradeAddresses[3]], tradeValues[4]);
tokens[tradeAddresses[0]][tradeAddresses[2]] = safeAdd(tokens[tradeAddresses[0]][tradeAddresses[2]], safeMul(tradeValues[4], ((1 ether) - tradeValues[6])) / (1 ether));
tokens[tradeAddresses[0]][feeAccount] = safeAdd(tokens[tradeAddresses[0]][feeAccount], safeMul(tradeValues[4], tradeValues[6]) / (1 ether));
tokens[tradeAddresses[1]][tradeAddresses[2]] = safeSub(tokens[tradeAddresses[1]][tradeAddresses[2]], safeMul(tradeValues[1], tradeValues[4]) / tradeValues[0]);
tokens[tradeAddresses[1]][tradeAddresses[3]] = safeAdd(tokens[tradeAddresses[1]][tradeAddresses[3]], safeMul(safeMul(((1 ether) - tradeValues[7]), tradeValues[1]), tradeValues[4]) / tradeValues[0] / (1 ether));
tokens[tradeAddresses[1]][feeAccount] = safeAdd(tokens[tradeAddresses[1]][feeAccount], safeMul(safeMul(tradeValues[7], tradeValues[1]), tradeValues[4]) / tradeValues[0] / (1 ether));
orderFills[orderHash] = safeAdd(orderFills[orderHash], tradeValues[4]);
lastActiveTransaction[tradeAddresses[2]] = block.number;
lastActiveTransaction[tradeAddresses[3]] = block.number;
}
}File 2 of 2: MVLToken
pragma solidity 0.4.23;
// File: contracts/token/ERC20Basic.sol
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
// File: contracts/token/ERC20.sol
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File: contracts/token/DetailedERC20.sol
contract DetailedERC20 is ERC20 {
string public name;
string public symbol;
uint8 public decimals;
constructor(string _name, string _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
// File: contracts/token/Ownable.sol
contract Ownable {
address public owner;
address public admin;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
modifier onlyOwnerOrAdmin() {
require(msg.sender != address(0) && (msg.sender == owner || msg.sender == admin));
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner public {
require(newOwner != address(0));
require(newOwner != owner);
require(newOwner != admin);
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
function setAdmin(address newAdmin) onlyOwner public {
require(admin != newAdmin);
require(owner != newAdmin);
admin = newAdmin;
}
}
// File: contracts/token/SafeMath.sol
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0 || b == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a); // overflow check
return c;
}
}
// File: contracts/token/MVLToken.sol
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
uint256 _totalSupply;
/**
* @dev total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev transfer token for 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) {
require(_to != address(0));
require(_value > 0);
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
contract ERC20Token is BasicToken, ERC20 {
using SafeMath for uint256;
mapping (address => mapping (address => uint256)) allowed;
function approve(address _spender, uint256 _value) public returns (bool) {
require(_value == 0 || allowed[msg.sender][_spender] == 0);
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
function increaseApproval(address _spender, uint256 _addedValue) public returns (bool success) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool success) {
uint256 oldValue = allowed[msg.sender][_spender];
if (_subtractedValue >= oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
contract BurnableToken is BasicToken, Ownable {
// events
event Burn(address indexed burner, uint256 amount);
// reduce sender balance and Token total supply
function burn(uint256 _value) onlyOwner public {
balances[msg.sender] = balances[msg.sender].sub(_value);
_totalSupply = _totalSupply.sub(_value);
emit Burn(msg.sender, _value);
emit Transfer(msg.sender, address(0), _value);
}
}
contract TokenLock is Ownable {
using SafeMath for uint256;
bool public transferEnabled = false; // indicates that token is transferable or not
bool public noTokenLocked = false; // indicates all token is released or not
struct TokenLockInfo { // token of `amount` cannot be moved before `time`
uint256 amount; // locked amount
uint256 time; // unix timestamp
}
struct TokenLockState {
uint256 latestReleaseTime;
TokenLockInfo[] tokenLocks; // multiple token locks can exist
}
mapping(address => TokenLockState) lockingStates;
event AddTokenLock(address indexed to, uint256 time, uint256 amount);
function unlockAllTokens() public onlyOwner {
noTokenLocked = true;
}
function enableTransfer(bool _enable) public onlyOwner {
transferEnabled = _enable;
}
// calculate the amount of tokens an address can use
function getMinLockedAmount(address _addr) view public returns (uint256 locked) {
uint256 i;
uint256 a;
uint256 t;
uint256 lockSum = 0;
// if the address has no limitations just return 0
TokenLockState storage lockState = lockingStates[_addr];
if (lockState.latestReleaseTime < now) {
return 0;
}
for (i=0; i<lockState.tokenLocks.length; i++) {
a = lockState.tokenLocks[i].amount;
t = lockState.tokenLocks[i].time;
if (t > now) {
lockSum = lockSum.add(a);
}
}
return lockSum;
}
function addTokenLock(address _addr, uint256 _value, uint256 _release_time) onlyOwnerOrAdmin public {
require(_addr != address(0));
require(_value > 0);
require(_release_time > now);
TokenLockState storage lockState = lockingStates[_addr]; // assigns a pointer. change the member value will update struct itself.
if (_release_time > lockState.latestReleaseTime) {
lockState.latestReleaseTime = _release_time;
}
lockState.tokenLocks.push(TokenLockInfo(_value, _release_time));
emit AddTokenLock(_addr, _release_time, _value);
}
}
contract MVLToken is BurnableToken, DetailedERC20, ERC20Token, TokenLock {
using SafeMath for uint256;
// events
event Approval(address indexed owner, address indexed spender, uint256 value);
string public constant symbol = "MVL";
string public constant name = "Mass Vehicle Ledger Token";
uint8 public constant decimals = 18;
uint256 public constant TOTAL_SUPPLY = 3*(10**10)*(10**uint256(decimals));
constructor() DetailedERC20(name, symbol, decimals) public {
_totalSupply = TOTAL_SUPPLY;
// initial supply belongs to owner
balances[owner] = _totalSupply;
emit Transfer(address(0x0), msg.sender, _totalSupply);
}
// modifiers
// checks if the address can transfer tokens
modifier canTransfer(address _sender, uint256 _value) {
require(_sender != address(0));
require(
(_sender == owner || _sender == admin) || (
transferEnabled && (
noTokenLocked ||
canTransferIfLocked(_sender, _value)
)
)
);
_;
}
function setAdmin(address newAdmin) onlyOwner public {
address oldAdmin = admin;
super.setAdmin(newAdmin);
approve(oldAdmin, 0);
approve(newAdmin, TOTAL_SUPPLY);
}
modifier onlyValidDestination(address to) {
require(to != address(0x0));
require(to != address(this));
require(to != owner);
_;
}
function canTransferIfLocked(address _sender, uint256 _value) public view returns(bool) {
uint256 after_math = balances[_sender].sub(_value);
return after_math >= getMinLockedAmount(_sender);
}
// override function using canTransfer on the sender address
function transfer(address _to, uint256 _value) onlyValidDestination(_to) canTransfer(msg.sender, _value) public returns (bool success) {
return super.transfer(_to, _value);
}
// transfer tokens from one address to another
function transferFrom(address _from, address _to, uint256 _value) onlyValidDestination(_to) canTransfer(_from, _value) public returns (bool success) {
// SafeMath.sub will throw if there is not enough balance.
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); // this will throw if we don't have enough allowance
// this event comes from BasicToken.sol
emit Transfer(_from, _to, _value);
return true;
}
function() public payable { // don't send eth directly to token contract
revert();
}
}