ETH Price: $2,510.63 (+0.75%)

Transaction Decoder

Block:
4809977 at Dec-28-2017 02:35:14 AM +UTC
Transaction Fee:
0.0048998 ETH $12.30
Gas Used:
97,996 Gas / 50 Gwei

Emitted Events:

1 BitDegreeToken.Transfer( from=0xE259Ece17FEef05BdeAd9689c6F1BC8E778c517B, to=[Sender] 0xd6e911edff4b1b3475fd276948324b98b295abd7, value=1160000000000000000000 )
2 BitDegreeCrowdsale.TokenPurchase( purchaser=[Sender] 0xd6e911edff4b1b3475fd276948324b98b295abd7, beneficiary=[Sender] 0xd6e911edff4b1b3475fd276948324b98b295abd7, value=116000000000000000, amount=1160000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x01dE7A62...2b261BdfD 20,665.164087911689501031 Eth20,665.280087911689501031 Eth0.116
0x1961B333...0838b6dEE
0xA9B2D2Be...080c00159
(BitDegree: Token Sale)
0xD6E911ED...8b295ABd7
0.12665482375 Eth
Nonce: 4
0.00575502375 Eth
Nonce: 5
0.1208998
(Ethermine)
799.299275688817095253 Eth799.304175488817095253 Eth0.0048998

Execution Trace

ETH 0.116 BitDegreeCrowdsale.CALL( )
  • BitDegreeToken.transferFrom( _from=0xE259Ece17FEef05BdeAd9689c6F1BC8E778c517B, _to=0xD6E911EDff4B1b3475Fd276948324b98b295ABd7, _value=1160000000000000000000 ) => ( True )
  • ETH 0.116 0x01de7a62197aab2a6a3a3ab8003671a2b261bdfd.CALL( )
    File 1 of 2: BitDegreeCrowdsale
    pragma solidity ^0.4.18;
    
    /**
     * @title SafeMath
     * @dev Math operations with safety checks that throw on error
     */
    library SafeMath {
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 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);
            return c;
        }
    }
    
    contract token {
        function transferFrom(address _from, address _to, uint256 _value) public returns (bool);
        function setStartTime(uint _startTime) external;
    }
    
    /**
     * @title BitDegree Crowdsale
     */
    contract BitDegreeCrowdsale {
        using SafeMath for uint256;
    
        // Investor contributions
        mapping(address => uint256) balances;
    
        // The token being sold
        token public reward;
    
        // Owner of the token
        address public owner;
    
        // Start and end timestamps
        uint public startTime;
        uint public endTime;
    
        // Address where funds are collected
        address public wallet;
    
        // Amount of tokens that were sold
        uint256 public tokensSold;
    
        // Soft cap in BDG tokens
        uint256 constant public softCap = 6250000 * (10**18);
    
        // Hard cap in BDG tokens
        uint256 constant public hardCap = 336600000 * (10**18);
    
        // Switched to true once token contract is notified of when to enable token transfers
        bool private isStartTimeSet = false;
    
        /**
         * @dev Event for token purchase logging
         * @param purchaser Address that paid for the tokens
         * @param beneficiary Address that got the tokens
         * @param value The amount that was paid (in wei)
         * @param amount The amount of tokens that were bought
         */
        event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
    
        /**
         * @dev Event for refund logging
         * @param receiver The address that received the refund
         * @param amount The amount that is being refunded (in wei)
         */
        event Refund(address indexed receiver, uint256 amount);
    
        /**
         * @param _startTime Unix timestamp for the start of the token sale
         * @param _endTime Unix timestamp for the end of the token sale
         * @param _wallet Ethereum address to which the invested funds are forwarded
         * @param _token Address of the token that will be rewarded for the investors
         * @param _owner Address of the owner of the smart contract who can execute restricted functions
         */
        function BitDegreeCrowdsale(uint256 _startTime, uint256 _endTime, address _wallet, address _token, address _owner)  public {
            require(_startTime >= now);
            require(_endTime >= _startTime);
            require(_wallet != address(0));
            require(_token != address(0));
            require(_owner != address(0));
    
            startTime = _startTime;
            endTime = _endTime;
            wallet = _wallet;
            owner = _owner;
            reward = token(_token);
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(msg.sender == owner);
            _;
        }
    
        /**
         * @dev Fallback function that can be used to buy tokens. Or in case of the owner, return ether to allow refunds.
         */
        function () external payable {
            if(msg.sender == wallet) {
                require(hasEnded() && tokensSold < softCap);
            } else {
                buyTokens(msg.sender);
            }
        }
    
        /**
         * @dev Function for buying tokens
         * @param beneficiary The address that should receive bought tokens
         */
        function buyTokens(address beneficiary) public payable {
            require(beneficiary != address(0));
            require(validPurchase());
    
            uint256 weiAmount = msg.value;
            uint256 returnToSender = 0;
    
            // Retrieve the current token rate
            uint256 rate = getRate();
    
            // Calculate token amount to be transferred
            uint256 tokens = weiAmount.mul(rate);
    
            // Distribute only the remaining tokens if final contribution exceeds hard cap
            if(tokensSold.add(tokens) > hardCap) {
                tokens = hardCap.sub(tokensSold);
                weiAmount = tokens.div(rate);
                returnToSender = msg.value.sub(weiAmount);
            }
    
            // update state
            tokensSold = tokensSold.add(tokens);
    
            // update balance
            balances[beneficiary] = balances[beneficiary].add(weiAmount);
    
            assert(reward.transferFrom(owner, beneficiary, tokens));
            TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
    
            // Forward funds
            wallet.transfer(weiAmount);
    
            // Allow transfers 2 weeks after hard cap is reached
            if(tokensSold == hardCap) {
                reward.setStartTime(now + 2 weeks);
            }
    
            // Notify token contract about sale end time
            if(!isStartTimeSet) {
                isStartTimeSet = true;
                reward.setStartTime(endTime + 2 weeks);
            }
    
            // Return funds that are over hard cap
            if(returnToSender > 0) {
                msg.sender.transfer(returnToSender);
            }
        }
    
        /**
         * @dev Internal function that is used to determine the current rate for token / ETH conversion
         * @return The current token rate
         */
        function getRate() internal constant returns (uint256) {
            if(now < (startTime + 1 weeks)) {
                return 11500;
            }
    
            if(now < (startTime + 2 weeks)) {
                return 11000;
            }
    
            if(now < (startTime + 3 weeks)) {
                return 10500;
            }
    
            return 10000;
        }
    
        /**
         * @dev Internal function that is used to check if the incoming purchase should be accepted.
         * @return True if the transaction can buy tokens
         */
        function validPurchase() internal constant returns (bool) {
            bool withinPeriod = now >= startTime && now <= endTime;
            bool nonZeroPurchase = msg.value != 0;
            bool hardCapNotReached = tokensSold < hardCap;
            return withinPeriod && nonZeroPurchase && hardCapNotReached;
        }
    
        /**
         * @return True if crowdsale event has ended
         */
        function hasEnded() public constant returns (bool) {
            return now > endTime || tokensSold >= hardCap;
        }
    
        /**
         * @dev Returns ether to token holders in case soft cap is not reached.
         */
        function claimRefund() external {
            require(hasEnded());
            require(tokensSold < softCap);
    
            uint256 amount = balances[msg.sender];
    
            if(address(this).balance >= amount) {
                balances[msg.sender] = 0;
                if (amount > 0) {
                    msg.sender.transfer(amount);
                    Refund(msg.sender, amount);
                }
            }
        }
    
        /**
        * @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) external constant returns (uint256 balance) {
            return balances[_owner];
        }
    
    }

    File 2 of 2: BitDegreeToken
    pragma solidity ^0.4.18;
    
    /**
     * @title SafeMath
     * @dev Math operations with safety checks that throw on error
     */
    library SafeMath {
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 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);
            return c;
        }
    }
    
    /**
     * @title ERC20Basic
     * @dev Simpler version of ERC20 interface
     * @dev see https://github.com/ethereum/EIPs/issues/179
     */
    contract ERC20Basic {
        uint256 public totalSupply;
        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);
    }
    
    /**
     * @title ERC20 interface
     * @dev see https://github.com/ethereum/EIPs/issues/20
     */
    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);
    }
    
    /**
     * @title Basic token
     * @dev Basic version of StandardToken, with no allowances.
     */
    contract BasicToken is ERC20Basic {
        using SafeMath for uint256;
    
        mapping(address => uint256) balances;
    
        /**
        * @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 <= 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);
            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];
        }
    
    }
    
    /**
     * @title Standard ERC20 token
     *
     * @dev Implementation of the basic standard token.
     * @dev https://github.com/ethereum/EIPs/issues/20
     * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
     */
    contract StandardToken is ERC20, BasicToken {
    
        mapping (address => mapping (address => uint256)) internal allowed;
    
    
        /**
         * @dev Transfer tokens from one address to another
         * @param _from address The address which you want to send tokens from
         * @param _to address The address which you want to transfer to
         * @param _value uint256 the amount of tokens to be transferred
         */
        function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
            require(_to != address(0));
            require(_value <= balances[_from]);
            require(_value <= allowed[_from][msg.sender]);
    
            balances[_from] = balances[_from].sub(_value);
            balances[_to] = balances[_to].add(_value);
            allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
            Transfer(_from, _to, _value);
            return true;
        }
    
        /**
         * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
         *
         * Beware that changing an allowance with this method brings the risk that someone may use both the old
         * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
         * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         * @param _spender The address which will spend the funds.
         * @param _value The amount of tokens to be spent.
         */
        function approve(address _spender, uint256 _value) public returns (bool) {
            allowed[msg.sender][_spender] = _value;
            Approval(msg.sender, _spender, _value);
            return true;
        }
    
        /**
         * @dev Function to check the amount of tokens that an owner allowed to a spender.
         * @param _owner address The address which owns the funds.
         * @param _spender address The address which will spend the funds.
         * @return A uint256 specifying the amount of tokens still available for the spender.
         */
        function allowance(address _owner, address _spender) public view returns (uint256) {
            return allowed[_owner][_spender];
        }
    
        /**
         * approve should be called when allowed[_spender] == 0. To increment
         * allowed value is better to use this function to avoid 2 calls (and wait until
         * the first transaction is mined)
         * From MonolithDAO Token.sol
         */
        function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
            allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
            Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
            return true;
        }
    
        function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
            uint oldValue = allowed[msg.sender][_spender];
            if (_subtractedValue > oldValue) {
                allowed[msg.sender][_spender] = 0;
            } else {
                allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
            }
            Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
            return true;
        }
    
    }
    
    /**
     * @title Ownable
     * @dev The Ownable contract has an owner address, and provides basic authorization control
     * functions, this simplifies the implementation of "user permissions".
     */
    contract Ownable {
        address public owner;
    
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
    
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        function Ownable() public {
            owner = msg.sender;
        }
    
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(msg.sender == owner);
            _;
        }
    
    
        /**
         * @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) public onlyOwner {
            require(newOwner != address(0));
            OwnershipTransferred(owner, newOwner);
            owner = newOwner;
        }
    
    }
    
    /**
     * @title Pausable
     * @dev Base contract which allows children to implement an emergency stop mechanism.
     */
    contract Pausable is Ownable {
        event Pause();
        event Unpause();
    
        bool public paused = false;
    
    
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         */
        modifier whenNotPaused() {
            require(!paused);
            _;
        }
    
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         */
        modifier whenPaused() {
            require(paused);
            _;
        }
    
        /**
         * @dev called by the owner to pause, triggers stopped state
         */
        function pause() onlyOwner whenNotPaused public {
            paused = true;
            Pause();
        }
    
        /**
         * @dev called by the owner to unpause, returns to normal state
         */
        function unpause() onlyOwner whenPaused public {
            paused = false;
            Unpause();
        }
    }
    
    /**
     * @title Pausable token
     *
     * @dev StandardToken modified with pausable transfers.
     **/
    contract PausableToken is StandardToken, Pausable {
    
        function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) {
            return super.transfer(_to, _value);
        }
    
        function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) {
            return super.transferFrom(_from, _to, _value);
        }
    
        function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) {
            return super.approve(_spender, _value);
        }
    
        function increaseApproval(address _spender, uint _addedValue) public whenNotPaused returns (bool success) {
            return super.increaseApproval(_spender, _addedValue);
        }
    
        function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool success) {
            return super.decreaseApproval(_spender, _subtractedValue);
        }
    }
    
    
    contract BitDegreeToken is PausableToken {
        string public constant name = "BitDegree Token";
        string public constant symbol = "BDG";
        uint8 public constant decimals = 18;
    
        uint256 private constant TOKEN_UNIT = 10 ** uint256(decimals);
    
        uint256 public constant totalSupply = 660000000 * TOKEN_UNIT;
        uint256 public constant publicAmount = 336600000 * TOKEN_UNIT; // Tokens for public
    
        uint public startTime;
        address public crowdsaleAddress;
    
        struct TokenLock { uint256 amount; uint duration; bool withdrawn; }
    
        TokenLock public foundationLock = TokenLock({
            amount: 66000000 * TOKEN_UNIT,
            duration: 360 days,
            withdrawn: false
        });
    
        TokenLock public teamLock = TokenLock({
            amount: 66000000 * TOKEN_UNIT,
            duration: 720 days,
            withdrawn: false
        });
    
        TokenLock public advisorLock = TokenLock({
            amount: 13200000 * TOKEN_UNIT,
            duration: 160 days,
            withdrawn: false
        });
    
        function BitDegreeToken() public {
            startTime = now + 70 days;
    
            balances[owner] = totalSupply;
            Transfer(address(0), owner, balances[owner]);
    
            lockTokens(foundationLock);
            lockTokens(teamLock);
            lockTokens(advisorLock);
        }
    
        function setCrowdsaleAddress(address _crowdsaleAddress) external onlyOwner {
            crowdsaleAddress = _crowdsaleAddress;
            assert(approve(crowdsaleAddress, publicAmount));
        }
    
        function withdrawLocked() external onlyOwner {
            if(unlockTokens(foundationLock)) foundationLock.withdrawn = true;
            if(unlockTokens(teamLock)) teamLock.withdrawn = true;
            if(unlockTokens(advisorLock)) advisorLock.withdrawn = true;
        }
    
        function lockTokens(TokenLock lock) internal {
            balances[owner] = balances[owner].sub(lock.amount);
            balances[address(0)] = balances[address(0)].add(lock.amount);
            Transfer(owner, address(0), lock.amount);
        }
    
        function unlockTokens(TokenLock lock) internal returns (bool) {
            uint lockReleaseTime = startTime + lock.duration;
    
            if(lockReleaseTime < now && lock.withdrawn == false) {
                balances[owner] = balances[owner].add(lock.amount);
                balances[address(0)] = balances[address(0)].sub(lock.amount);
                Transfer(address(0), owner, lock.amount);
                return true;
            }
    
            return false;
        }
    
        function setStartTime(uint _startTime) external {
            require(msg.sender == crowdsaleAddress);
            if(_startTime < startTime) {
                startTime = _startTime;
            }
        }
    
        function transfer(address _to, uint _value) public returns (bool) {
            // Only possible after ICO ends
            require(now >= startTime);
    
            return super.transfer(_to, _value);
        }
    
        function transferFrom(address _from, address _to, uint _value) public returns (bool) {
            // Only owner's tokens can be transferred before ICO ends
            if (now < startTime)
                require(_from == owner);
    
            return super.transferFrom(_from, _to, _value);
        }
    
        function transferOwnership(address newOwner) public onlyOwner {
            require(now >= startTime);
            super.transferOwnership(newOwner);
        }
    }