ETH Price: $2,265.24 (-5.90%)

Transaction Decoder

Block:
8132264 at Jul-11-2019 09:13:47 PM +UTC
Transaction Fee:
0.0045189 ETH $10.24
Gas Used:
45,189 Gas / 100 Gwei

Emitted Events:

0 Legolas.Transfer( _from=[Sender] 0x99e245dde532cc502fc9caba1a1843c1bc84a643, _to=[Receiver] Exchange, _value=2051764625995 )
1 Exchange.Deposit( token=Legolas, user=[Sender] 0x99e245dde532cc502fc9caba1a1843c1bc84a643, amount=2051764625995, balance=2051764625995 )

Account State Difference:

  Address   Before After State Difference Code
0x123aB195...201af056f
0x2a0c0DBE...44050c208
(IDEX)
(Fee Recipient: 0x497...99C)
0.003101324 Eth0.007620224 Eth0.0045189
0x99e245dD...1Bc84a643
0.043787632443288539 Eth
Nonce: 84
0.039268732443288539 Eth
Nonce: 85
0.0045189

Execution Trace

Exchange.depositToken( token=0x123aB195DD38B1b40510d467a6a359b201af056f, amount=2051764625995 )
  • Legolas.transferFrom( _from=0x99e245dDE532Cc502FC9CABa1A1843C1Bc84a643, _to=0x2a0c0DBEcC7E4D658f48E01e3fA353F44050c208, _value=2051764625995 ) => ( success=True )
    File 1 of 2: Exchange
    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: Legolas
    pragma solidity ^0.4.13;
    
    contract EIP20Interface {
        /* This is a slight change to the ERC20 base standard.
        function totalSupply() constant returns (uint256 supply);
        is replaced with:
        uint256 public totalSupply;
        This automatically creates a getter function for the totalSupply.
        This is moved to the base contract since public getter functions are not
        currently recognised as an implementation of the matching abstract
        function by the compiler.
        */
        /// total amount of tokens
        uint256 public totalSupply;
    
        /// @param _owner The address from which the balance will be retrieved
        /// @return The balance
        function balanceOf(address _owner) public view returns (uint256 balance);
    
        /// @notice send `_value` token to `_to` from `msg.sender`
        /// @param _to The address of the recipient
        /// @param _value The amount of token to be transferred
        /// @return Whether the transfer was successful or not
        function transfer(address _to, uint256 _value) public returns (bool success);
    
        /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
        /// @param _from The address of the sender
        /// @param _to The address of the recipient
        /// @param _value The amount of token to be transferred
        /// @return Whether the transfer was successful or not
        function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
    
        /// @notice `msg.sender` approves `_spender` to spend `_value` tokens
        /// @param _spender The address of the account able to transfer the tokens
        /// @param _value The amount of tokens to be approved for transfer
        /// @return Whether the approval was successful or not
        function approve(address _spender, uint256 _value) public returns (bool success);
    
        /// @param _owner The address of the account owning tokens
        /// @param _spender The address of the account able to transfer the tokens
        /// @return Amount of remaining tokens allowed to spent
        function allowance(address _owner, address _spender) public view returns (uint256 remaining);
    
        // solhint-disable-next-line no-simple-event-func-name
        event Transfer(address indexed _from, address indexed _to, uint256 _value);
        event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    }
    
    contract Ownable {
        address public owner;
        address public newOwner;
    
        event OwnershipTransferred(address indexed _from, address indexed _to);
    
        modifier onlyOwner() {
            require(msg.sender == owner);
            _;
        }
    
        function Ownable() public {
            owner = msg.sender;
        }
    
        /// @notice Transfer ownership from `owner` to `newOwner`
        /// @param _newOwner The new contract owner
        function transferOwnership(address _newOwner) public onlyOwner {
            if (_newOwner != address(0)) {
                newOwner = _newOwner;
            }
        }
    
        /// @notice accept ownership of the contract
        function acceptOwnership() public {
            require(msg.sender == newOwner);
            OwnershipTransferred(owner, newOwner);
            owner = newOwner;
        }
    
    }
    
    contract LegolasBase is Ownable {
    
        mapping (address => uint256) public balances;
    
        // Initial amount received from the pre-sale (doesn't include bonus)
        mapping (address => uint256) public initialAllocations;
        // Initial amount received from the pre-sale (includes bonus)
        mapping (address => uint256) public allocations;
        // False if part of the allocated amount is spent
        mapping (uint256 => mapping(address => bool)) public eligibleForBonus;
        // unspent allocated amount by period
        mapping (uint256 => uint256) public unspentAmounts;
        // List of founders addresses
        mapping (address => bool) public founders;
        // List of advisors addresses
        mapping (address => bool) public advisors;
    
        // Release dates for adviors: one twelfth released each month.
        uint256[12] public ADVISORS_LOCK_DATES = [1521072000, 1523750400, 1526342400,
                                           1529020800, 1531612800, 1534291200,
                                           1536969600, 1539561600, 1542240000,
                                           1544832000, 1547510400, 1550188800];
        // Release dates for founders: After one year, one twelfth released each month.
        uint256[12] public FOUNDERS_LOCK_DATES = [1552608000, 1555286400, 1557878400,
                                           1560556800, 1563148800, 1565827200,
                                           1568505600, 1571097600, 1573776000,
                                           1576368000, 1579046400, 1581724800];
    
        // Bonus dates: each 6 months during 2 years
        uint256[4] public BONUS_DATES = [1534291200, 1550188800, 1565827200, 1581724800];
    
        /// @param _address The address from which the locked amount will be retrieved
        /// @return The amount locked for _address.
        function getLockedAmount(address _address) internal view returns (uint256 lockedAmount) {
            // Only founders and advisors have locks
            if (!advisors[_address] && !founders[_address]) return 0;
            // Determine release dates
            uint256[12] memory lockDates = advisors[_address] ? ADVISORS_LOCK_DATES : FOUNDERS_LOCK_DATES;
            // Determine how many twelfths are locked
            for (uint8 i = 11; i >= 0; i--) {
                if (now >= lockDates[i]) {
                    return (allocations[_address] / 12) * (11 - i);
                }
            }
            return allocations[_address];
        }
    
        function updateBonusEligibity(address _from) internal {
            if (now < BONUS_DATES[3] &&
                initialAllocations[_from] > 0 &&
                balances[_from] < allocations[_from]) {
                for (uint8 i = 0; i < 4; i++) {
                    if (now < BONUS_DATES[i] && eligibleForBonus[BONUS_DATES[i]][_from]) {
                        unspentAmounts[BONUS_DATES[i]] -= initialAllocations[_from];
                        eligibleForBonus[BONUS_DATES[i]][_from] = false;
                    }
                }
            }
        }
    }
    
    contract EIP20 is EIP20Interface, LegolasBase {
    
        uint256 constant private MAX_UINT256 = 2**256 - 1;
        mapping (address => mapping (address => uint256)) public allowed;
    
    
        /*
        NOTE:
        The following variables are OPTIONAL vanities. One does not have to include them.
        They allow one to customise the token contract & in no way influences the core functionality.
        Some wallets/interfaces might not even bother to look at this information.
        */
        string public name;                   //fancy name: eg Simon Bucks
        uint8 public decimals;                //How many decimals to show.
        string public symbol;                 //An identifier: eg SBX
    
        function EIP20(
            uint256 _initialAmount,
            string _tokenName,
            uint8 _decimalUnits,
            string _tokenSymbol
        ) public {
            balances[msg.sender] = _initialAmount;               // Give the creator all initial tokens
            totalSupply = _initialAmount;                        // Update total supply
            name = _tokenName;                                   // Set the name for display purposes
            decimals = _decimalUnits;                            // Amount of decimals for display purposes
            symbol = _tokenSymbol;                               // Set the symbol for display purposes
        }
    
        function transfer(address _to, uint256 _value) public returns (bool success) {
            require(balances[msg.sender] >= _value);
            // Check locked amount
            require(balances[msg.sender] - _value >= getLockedAmount(msg.sender));
            balances[msg.sender] -= _value;
            balances[_to] += _value;
    
            // Bonus lost if balance is lower than the original allocation
            updateBonusEligibity(msg.sender);
    
            Transfer(msg.sender, _to, _value);
            return true;
        }
    
        function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
            uint256 allowance = allowed[_from][msg.sender];
            require(balances[_from] >= _value && allowance >= _value);
    
            // Check locked amount
            require(balances[_from] - _value >= getLockedAmount(_from));
    
            balances[_to] += _value;
            balances[_from] -= _value;
            if (allowance < MAX_UINT256) {
                allowed[_from][msg.sender] -= _value;
            }
    
            // Bonus lost if balance is lower than the original allocation
            updateBonusEligibity(_from);
    
            Transfer(_from, _to, _value);
            return true;
        }
    
        function balanceOf(address _owner) public view returns (uint256 balance) {
            return balances[_owner];
        }
    
        function approve(address _spender, uint256 _value) public returns (bool success) {
            allowed[msg.sender][_spender] = _value;
            Approval(msg.sender, _spender, _value);
            return true;
        }
    
        function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
            return allowed[_owner][_spender];
        }
    }
    
    contract Legolas is EIP20 {
    
        // Standard ERC20 information
        string  constant NAME = "LGO Token";
        string  constant SYMBOL = "LGO";
        uint8   constant DECIMALS = 8;
        uint256 constant UNIT = 10**uint256(DECIMALS);
    
        uint256 constant onePercent = 181415052000000;
    
        // 5% for advisors
        uint256 constant ADVISORS_AMOUNT =   5 * onePercent;
        // 15% for founders
        uint256 constant FOUNDERS_AMOUNT =  15 * onePercent;
        // 60% sold in pre-sale
        uint256 constant HOLDERS_AMOUNT  =  60 * onePercent;
        // 20% reserve
        uint256 constant RESERVE_AMOUNT  =  20 * onePercent;
        // ADVISORS_AMOUNT + FOUNDERS_AMOUNT + HOLDERS_AMOUNT +RESERVE_AMOUNT
        uint256 constant INITIAL_AMOUNT  = 100 * onePercent;
        // 20% for holder bonus
        uint256 constant BONUS_AMOUNT    =  20 * onePercent;
        // amount already allocated to advisors
        uint256 public advisorsAllocatedAmount = 0;
        // amount already allocated to funders
        uint256 public foundersAllocatedAmount = 0;
        // amount already allocated to holders
        uint256 public holdersAllocatedAmount = 0;
        // list of all initial holders
        address[] initialHolders;
        // not distributed because the defaut value is false
        mapping (uint256 => mapping(address => bool)) bonusNotDistributed;
    
        event Allocate(address _address, uint256 _value);
    
        function Legolas() EIP20( // EIP20 constructor
            INITIAL_AMOUNT + BONUS_AMOUNT,
            NAME,
            DECIMALS,
            SYMBOL
        ) public {}
    
        /// @param _address The address of the recipient
        /// @param _amount Amount of the allocation
        /// @param _type Type of the recipient. 0 for advisor, 1 for founders.
        /// @return Whether the allocation was successful or not
        function allocate(address _address, uint256 _amount, uint8 _type) public onlyOwner returns (bool success) {
            // one allocations by address
            require(allocations[_address] == 0);
    
            if (_type == 0) { // advisor
                // check allocated amount
                require(advisorsAllocatedAmount + _amount <= ADVISORS_AMOUNT);
                // increase allocated amount
                advisorsAllocatedAmount += _amount;
                // mark address as advisor
                advisors[_address] = true;
            } else if (_type == 1) { // founder
                // check allocated amount
                require(foundersAllocatedAmount + _amount <= FOUNDERS_AMOUNT);
                // increase allocated amount
                foundersAllocatedAmount += _amount;
                // mark address as founder
                founders[_address] = true;
            } else {
                // check allocated amount
                require(holdersAllocatedAmount + _amount <= HOLDERS_AMOUNT + RESERVE_AMOUNT);
                // increase allocated amount
                holdersAllocatedAmount += _amount;
            }
            // set allocation
            allocations[_address] = _amount;
            initialAllocations[_address] = _amount;
    
            // increase balance
            balances[_address] += _amount;
    
            // update variables for bonus distribution
            for (uint8 i = 0; i < 4; i++) {
                // increase unspent amount
                unspentAmounts[BONUS_DATES[i]] += _amount;
                // initialize bonus eligibility
                eligibleForBonus[BONUS_DATES[i]][_address] = true;
                bonusNotDistributed[BONUS_DATES[i]][_address] = true;
            }
    
            // add to initial holders list
            initialHolders.push(_address);
    
            Allocate(_address, _amount);
    
            return true;
        }
    
        /// @param _address Holder address.
        /// @param _bonusDate Date of the bonus to distribute.
        /// @return Whether the bonus distribution was successful or not
        function claimBonus(address _address, uint256 _bonusDate) public returns (bool success) {
            /// bonus date must be past
            require(_bonusDate <= now);
            /// disrtibute bonus only once
            require(bonusNotDistributed[_bonusDate][_address]);
            /// disrtibute bonus only if eligible
            require(eligibleForBonus[_bonusDate][_address]);
    
            // calculate the bonus for one holded LGO
            uint256 bonusByLgo = (BONUS_AMOUNT / 4) / unspentAmounts[_bonusDate];
    
            // distribute the bonus
            uint256 holderBonus = initialAllocations[_address] * bonusByLgo;
            balances[_address] += holderBonus;
            allocations[_address] += holderBonus;
    
            // set bonus as distributed
            bonusNotDistributed[_bonusDate][_address] = false;
            return true;
        }
    }