Latest 25 transactions from a total of 3120 transactions

TxHash Age From To Value [TxFee]
0xd63b1067b83243f75df832fe907c4cccdeb937010bb178be4554e4e60866458d14 days 20 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x745f4508ee3b001bbd717f09a26d540c708b32319e67eeaad000fa8f62213f1614 days 21 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xe0c7785ce4de81ede1d74139da44d8b274914dea669951bc79193c70eb0d0d6e14 days 22 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x4bd1372dae7afa006d525c78886e9ba4a34a00c980f33d8f803fa982dcf7f2eb14 days 23 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xaccdb9bb0647ff048438448a33002d6cb69d6f635e008fd2fba2d91663713cf915 days 15 mins ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xbc7945d53eec253f0c0209258bff2bfa1e54f343b28abc7159cb7009ecd5de3f15 days 1 hr ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xb2dee138126777fe49ffe3835c9404a503d435f1a24079443504e4f25c366af815 days 2 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x3d0ee7a90448a320fe6c08133f5bdacb992bd4f5106279279cbb14abe5ecb41a15 days 3 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xab482bb27349cc91f94e86756aaebcb89c1dada0a4a13b4ae057c07b1247c75515 days 4 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xef475738835325be1a30d59f722f8b372a1d3887af94f0543469b8941317923f15 days 5 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x40ad56a5526b76da7e8d892a0cc58d1cef5a151be443a2a37631328100bcbd2e15 days 6 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xb9c83e0e018a9c85f16f984b7e871f10ac2c75cf1a0e667d45f9ba533d5bc41315 days 7 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x6a0c62d33f1eeab87fdd0b2842ee8bbdd60635a3a20afbbcbe03c96f580de05115 days 8 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x98111187a83ec6728b559749c86065b4d27407bda36c431f7f4cad94a822057215 days 9 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x5a7d6c2deb8883d02f764fd2ab96bd4c78183ecd1cecbce3c6adb946a3e339b115 days 10 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x8e2e142152e70dd0e5f5cbf26b4656974288dd6434aced2ec7b90d1b94a4a01a15 days 11 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x2397c08bf2826e32e7772de2fd1cb6814683dea3503f0353afd7bbf854b2b87615 days 12 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x0ebc243b06f90a9da165517288af795cf0b6b68cd712071a024947678b9bb61415 days 13 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x01d094e49ce1ca9c99df3d9ee13650d95c9e811ea612b35866f7916e94b643a615 days 14 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x126c9fbf0c7613696cc9c1dca2f39f4108ea9555cfd8ea3c50dd1d155553f33e15 days 15 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x88b21b812293f6894639c0d2b120c02518978de2cd1244e8795d63322771637015 days 16 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xab3dcf93fcb1530b5828e5e4a3137adc03ca67645b030c60396be1a07fed43ab15 days 17 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x4a321d9599eba83f28db4df58f63d314f8f4edf4de7d98f91e8c156c8dc4648715 days 18 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0x5f39ebc0192b46959b0b09a542a36f92a71ccfb8323d2942d97a00227733114215 days 19 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
0xe1167b941a2eca939a1f70546f37b6281e32f31f288deb95232d45e1ad1d8e8a15 days 20 hrs ago0xf001a51533bcd531d7a2f40a4579afcc19038c14  IN   0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether0.000055326
[ Download CSV Export  ] 
 Internal Transactions as a result of Contract Execution
 Latest 22 Internal Transactions

ParentTxHash Block Age From To Value
0x1d77b97f2bf9d3f279cb91d0b68bd3d3b1ec17a0e4ba40e022a657ba6f2f673c2939982140 days 14 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0x1d77b97f2bf9d3f279cb91d0b68bd3d3b1ec17a0e4ba40e022a657ba6f2f673c2939982140 days 14 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0x7cd5a0b9074eaf1ad75c532436f28e720e87e73fd75825aa7d6a1e2b6182d0c02939821140 days 15 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0x7cd5a0b9074eaf1ad75c532436f28e720e87e73fd75825aa7d6a1e2b6182d0c02939821140 days 15 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0xd97e669b19b5d4eb9ababeeebc4daf1c5069e780e5ba6937e99490d506069d872938942140 days 18 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0xd97e669b19b5d4eb9ababeeebc4daf1c5069e780e5ba6937e99490d506069d872938942140 days 18 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0xeb4f088816f569cd5ad10661460704f751d9bf822f36cf559e4cf4ef2502928c2929269142 days 11 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0xeb4f088816f569cd5ad10661460704f751d9bf822f36cf559e4cf4ef2502928c2929269142 days 11 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0x4300684f878ef73a7bc090a94c04dfa273f47c2e69a5a82060a85935cd7049c02929151142 days 11 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0x4300684f878ef73a7bc090a94c04dfa273f47c2e69a5a82060a85935cd7049c02929151142 days 11 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0x20aeca57b946b1444792d3e144d7eb727706e3cbb088b0e3b10e34b2d2b97a792928230142 days 15 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0x20aeca57b946b1444792d3e144d7eb727706e3cbb088b0e3b10e34b2d2b97a792928230142 days 15 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0x83af75e968277ad60cc34c005945dc9f26b1bcecaff20db9c56e4b932744fc4c2923313143 days 11 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0x83af75e968277ad60cc34c005945dc9f26b1bcecaff20db9c56e4b932744fc4c2923313143 days 11 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0x1b0d00f72a20a9b1c90813aa6e71cdd8544522d2bcc7efef34ba41b60e0569922923196143 days 12 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0x1b0d00f72a20a9b1c90813aa6e71cdd8544522d2bcc7efef34ba41b60e0569922923196143 days 12 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0xf5860bfa7a3bcac1a3b885371fa60a0828d777550ebfaeb16801beecfee5efcd2923036143 days 13 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0xf5860bfa7a3bcac1a3b885371fa60a0828d777550ebfaeb16801beecfee5efcd2923036143 days 13 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0xe932bc082b2d86181a333529c03ccc702e696b7488f4312763156de81c6891182922156143 days 16 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0xe932bc082b2d86181a333529c03ccc702e696b7488f4312763156de81c6891182922156143 days 16 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
0xcacf2d3c5abda91de50bc4996f50b06ff232f473dcafe6b1555bfc3c3806d1432921995143 days 17 hrs ago0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0x62d6203411988089cb6059c6370b407ab2010eb60 Ether
0xcacf2d3c5abda91de50bc4996f50b06ff232f473dcafe6b1555bfc3c3806d1432921995143 days 17 hrs ago0xc48ea9d53c243867b71fadf7e57a4caf6642f8de0xd41d4b54013a622eaec3d6f35072b6a5e827c0ef0 Ether
[ Download CSV Export  ] 
Warning: The Compiled Contract might be susceptible to ExpExponentCleanup (medium/high-severity), EventStructWrongData (very low-severity) SolidityCompiler Bugs.

Contract Source Code Verified (Exact Match)
Contract Name: DogeToken
Compiler Text: v0.4.24+commit.e67f0147
Optimization Enabled: Yes
Runs (Optimiser):  200



  Contract Source Code   Find Similiar Contracts

pragma solidity ^0.4.8;

/*
This Token Contract implements the standard token functionality (https://github.com/ethereum/EIPs/issues/20) as well as the following OPTIONAL extras intended for use by humans.

In other words. This is intended for deployment in something like a Token Factory or Mist wallet, and then used by humans.
Imagine coins, currencies, shares, voting weight, etc.
Machine-based, rapid creation of many tokens would not necessarily need these extra features or will be minted in other manners.

1) Initial Finite Supply (upon creation one specifies how much is minted).
2) In the absence of a token registry: Optional Decimal, Symbol & Name.
3) Optional approveAndCall() functionality to notify a contract if an approval() has occurred.

.*/

/*
You should inherit from StandardToken or, for a token like you would want to
deploy in something like Mist, see HumanStandardToken.sol.
(This implements ONLY the standard functions and NOTHING else.
If you deploy this, you won't have anything useful.)

Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20
.*/
pragma solidity ^0.4.8;

// Abstract contract for the full ERC 20 Token standard
// https://github.com/ethereum/EIPs/issues/20
pragma solidity ^0.4.8;

contract Token {
    /* This is a slight change to the ERC20 base standard.
    function totalSupply() view 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);

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}


contract StandardToken is Token {

    function transfer(address _to, uint256 _value) public returns (bool success) {
        //Default assumes totalSupply can't be over max (2^256 - 1).
        //If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
        //Replace the if with this one instead.
        //require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
        require(balances[msg.sender] >= _value);
        balances[msg.sender] -= _value;
        balances[_to] += _value;
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        //same as above. Replace this line with the following if you want to protect against wrapping uints.
        //require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]);
        require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
        balances[_to] += _value;
        balances[_from] -= _value;
        allowed[_from][msg.sender] -= _value;
        emit 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;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
        return allowed[_owner][_spender];
    }

    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;
}


pragma solidity ^0.4.8;

contract HumanStandardToken is StandardToken {

    /* Public variables of the token */

    /*
    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. ie. There could 1000 base units with 3 decimals. Meaning 0.980 SBX = 980 base units. It's like comparing 1 wei to 1 ether.
    string public symbol;                 //An identifier: eg SBX
    string public version = 'H0.1';       //human 0.1 standard. Just an arbitrary versioning scheme.

    constructor (
        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
    }

    /* Approves and then calls the receiving contract */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);

        //call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn't have to include a contract in here just for this.
        //receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
        //it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.
        require(_spender.call(bytes4(bytes32(keccak256("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData));
        return true;
    }
}

pragma solidity ^0.4.15;

library Set {
    // We define a new struct datatype that will be used to
    // hold its data in the calling contract.
    struct Data { 
        mapping(uint => bool) flags; 
    }

    // Note that the first parameter is of type "storage
    // reference" and thus only its storage address and not
    // its contents is passed as part of the call.  This is a
    // special feature of library functions.  It is idiomatic
    // to call the first parameter 'self', if the function can
    // be seen as a method of that object.
    function insert(Data storage self, uint value) public returns (bool) {
        if (self.flags[value])
            return false; // already there
        self.flags[value] = true;
        return true;
    }

    function remove(Data storage self, uint value) public returns (bool) {
        if (!self.flags[value])
            return false; // not there
        self.flags[value] = false;
        return true;
    }

    function contains(Data storage self, uint value) public view returns (bool) {
        return self.flags[value];
    }
}
pragma solidity ^0.4.19;

// Interface contract to be implemented by DogeToken
contract TransactionProcessor {
    function processTransaction(bytes txn, uint txHash, bytes20 operatorPublicKeyHash, address superblockSubmitterAddress) public returns (uint);
}

// Bitcoin transaction parsing library - modified for DOGE

// Copyright 2016 rain <https://keybase.io/rain>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// https://en.bitcoin.it/wiki/Protocol_documentation#tx
//
// Raw Bitcoin transaction structure:
//
// field     | size | type     | description
// version   | 4    | int32    | transaction version number
// n_tx_in   | 1-9  | var_int  | number of transaction inputs
// tx_in     | 41+  | tx_in[]  | list of transaction inputs
// n_tx_out  | 1-9  | var_int  | number of transaction outputs
// tx_out    | 9+   | tx_out[] | list of transaction outputs
// lock_time | 4    | uint32   | block number / timestamp at which tx locked
//
// Transaction input (tx_in) structure:
//
// field      | size | type     | description
// previous   | 36   | outpoint | Previous output transaction reference
// script_len | 1-9  | var_int  | Length of the signature script
// sig_script | ?    | uchar[]  | Script for confirming transaction authorization
// sequence   | 4    | uint32   | Sender transaction version
//
// OutPoint structure:
//
// field      | size | type     | description
// hash       | 32   | char[32] | The hash of the referenced transaction
// index      | 4    | uint32   | The index of this output in the referenced transaction
//
// Transaction output (tx_out) structure:
//
// field         | size | type     | description
// value         | 8    | int64    | Transaction value (Satoshis)
// pk_script_len | 1-9  | var_int  | Length of the public key script
// pk_script     | ?    | uchar[]  | Public key as a Bitcoin script.
//
// Variable integers (var_int) can be encoded differently depending
// on the represented value, to save space. Variable integers always
// precede an array of a variable length data type (e.g. tx_in).
//
// Variable integer encodings as a function of represented value:
//
// value           | bytes  | format
// <0xFD (253)     | 1      | uint8
// <=0xFFFF (65535)| 3      | 0xFD followed by length as uint16
// <=0xFFFF FFFF   | 5      | 0xFE followed by length as uint32
// -               | 9      | 0xFF followed by length as uint64
//
// Public key scripts `pk_script` are set on the output and can
// take a number of forms. The regular transaction script is
// called 'pay-to-pubkey-hash' (P2PKH):
//
// OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
//
// OP_x are Bitcoin script opcodes. The bytes representation (including
// the 0x14 20-byte stack push) is:
//
// 0x76 0xA9 0x14 <pubKeyHash> 0x88 0xAC
//
// The <pubKeyHash> is the ripemd160 hash of the sha256 hash of
// the public key, preceded by a network version byte. (21 bytes total)
//
// Network version bytes: 0x00 (mainnet); 0x6f (testnet); 0x34 (namecoin)
//
// The Bitcoin address is derived from the pubKeyHash. The binary form is the
// pubKeyHash, plus a checksum at the end.  The checksum is the first 4 bytes
// of the (32 byte) double sha256 of the pubKeyHash. (25 bytes total)
// This is converted to base58 to form the publicly used Bitcoin address.
// Mainnet P2PKH transaction scripts are to addresses beginning with '1'.
//
// P2SH ('pay to script hash') scripts only supply a script hash. The spender
// must then provide the script that would allow them to redeem this output.
// This allows for arbitrarily complex scripts to be funded using only a
// hash of the script, and moves the onus on providing the script from
// the spender to the redeemer.
//
// The P2SH script format is simple:
//
// OP_HASH160 <scriptHash> OP_EQUAL
//
// 0xA9 0x14 <scriptHash> 0x87
//
// The <scriptHash> is the ripemd160 hash of the sha256 hash of the
// redeem script. The P2SH address is derived from the scriptHash.
// Addresses are the scriptHash with a version prefix of 5, encoded as
// Base58check. These addresses begin with a '3'.

pragma solidity ^0.4.19;

// parse a raw bitcoin transaction byte array
library DogeTx {

    uint constant p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f;  // secp256k1
    uint constant q = (p + 1) / 4;

    // Error codes
    uint constant ERR_INVALID_HEADER = 10050;
    uint constant ERR_COINBASE_INDEX = 10060; // coinbase tx index within Litecoin merkle isn't 0
    uint constant ERR_NOT_MERGE_MINED = 10070; // trying to check AuxPoW on a block that wasn't merge mined
    uint constant ERR_FOUND_TWICE = 10080; // 0xfabe6d6d found twice
    uint constant ERR_NO_MERGE_HEADER = 10090; // 0xfabe6d6d not found
    uint constant ERR_NOT_IN_FIRST_20 = 10100; // chain Merkle root isn't in the first 20 bytes of coinbase tx
    uint constant ERR_CHAIN_MERKLE = 10110;
    uint constant ERR_PARENT_MERKLE = 10120;
    uint constant ERR_PROOF_OF_WORK = 10130;

    // AuxPoW block fields
    struct AuxPoW {
        // uint firstBytes;

        uint scryptHash;

        uint txHash;

        uint coinbaseMerkleRoot; // Merkle root of auxiliary block hash tree; stored in coinbase tx field
        uint[] chainMerkleProof; // proves that a given Dogecoin block hash belongs to a tree with the above root
        uint dogeHashIndex; // index of Doge block hash within block hash tree
        uint coinbaseMerkleRootCode; // encodes whether or not the root was found properly

        uint parentMerkleRoot; // Merkle root of transaction tree from parent Litecoin block header
        uint[] parentMerkleProof; // proves that coinbase tx belongs to a tree with the above root
        uint coinbaseTxIndex; // index of coinbase tx within Litecoin tx tree

        uint parentNonce;
    }

    // Dogecoin block header stored as a struct, mostly for readability purposes.
    // BlockHeader structs can be obtained by parsing a block header's first 80 bytes
    // with parseHeaderBytes.
    struct BlockHeader {
        uint32 version;
        uint32 time;
        uint32 bits;
        uint32 nonce;
        uint blockHash;
        uint prevBlock;
        uint merkleRoot;
    }

    // Convert a variable integer into something useful and return it and
    // the index to after it.
    function parseVarInt(bytes txBytes, uint pos) private pure returns (uint, uint) {
        // the first byte tells us how big the integer is
        uint8 ibit = uint8(txBytes[pos]);
        pos += 1;  // skip ibit

        if (ibit < 0xfd) {
            return (ibit, pos);
        } else if (ibit == 0xfd) {
            return (getBytesLE(txBytes, pos, 16), pos + 2);
        } else if (ibit == 0xfe) {
            return (getBytesLE(txBytes, pos, 32), pos + 4);
        } else if (ibit == 0xff) {
            return (getBytesLE(txBytes, pos, 64), pos + 8);
        }
    }
    // convert little endian bytes to uint
    function getBytesLE(bytes data, uint pos, uint bits) internal pure returns (uint) {
        if (bits == 8) {
            return uint8(data[pos]);
        } else if (bits == 16) {
            return uint16(data[pos])
                 + uint16(data[pos + 1]) * 2 ** 8;
        } else if (bits == 32) {
            return uint32(data[pos])
                 + uint32(data[pos + 1]) * 2 ** 8
                 + uint32(data[pos + 2]) * 2 ** 16
                 + uint32(data[pos + 3]) * 2 ** 24;
        } else if (bits == 64) {
            return uint64(data[pos])
                 + uint64(data[pos + 1]) * 2 ** 8
                 + uint64(data[pos + 2]) * 2 ** 16
                 + uint64(data[pos + 3]) * 2 ** 24
                 + uint64(data[pos + 4]) * 2 ** 32
                 + uint64(data[pos + 5]) * 2 ** 40
                 + uint64(data[pos + 6]) * 2 ** 48
                 + uint64(data[pos + 7]) * 2 ** 56;
        }
    }

    struct ParseTransactionVariablesStruct {
        uint pos;
        bytes20 output_public_key_hash;
        uint output_value;
        uint16 outputIndex;
        bytes32 inputPubKey;
        bool inputPubKeyOdd;
    }

    // Parses a doge tx
    // Inputs
    // txBytes: tx byte array
    // expected_output_public_key_hash: lock address (actually, it's public key hash expected to be on 1st or 2nd output, require() fails otherwise)
    // Outputs
    // output_value: amount sent to the lock address in satoshis
    // inputPubKey: "x" axis value of the public key used to sign the first output
    // inputPubKeyOdd: Indicates inputPubKey odd bit
    // outputIndex: number of output where expected_output_address was found

    function parseTransaction(bytes txBytes, bytes20 expected_output_public_key_hash) internal pure
             returns (uint, bytes32, bool, uint16)
    {
        ParseTransactionVariablesStruct memory variables;
        uint[] memory input_script_lens;
        uint[] memory input_script_starts;
        uint[] memory output_script_lens;
        uint[] memory output_script_starts;
        uint[] memory output_values;

        variables.pos = 4;  // skip version
        (input_script_starts, input_script_lens, variables.pos) = scanInputs(txBytes, variables.pos, 0);

        (variables.inputPubKey, variables.inputPubKeyOdd) = getInputPubKey(txBytes, input_script_starts[0]);

        (output_values, output_script_starts, output_script_lens, variables.pos) = scanOutputs(txBytes, variables.pos, 2);
        // The output we are looking for should be the first or the second output
        variables.output_public_key_hash = parseP2PKHOutputScript(txBytes, output_script_starts[0], output_script_lens[0]);
        variables.output_value = output_values[0];
        variables.outputIndex = 0;

        if (variables.output_public_key_hash != expected_output_public_key_hash) {
            variables.output_public_key_hash = parseP2PKHOutputScript(txBytes, output_script_starts[1], output_script_lens[1]);
            variables.output_value = output_values[1];
            variables.outputIndex = 1;
        }
        require(variables.output_public_key_hash == expected_output_public_key_hash);

        return (variables.output_value, variables.inputPubKey, variables.inputPubKeyOdd, variables.outputIndex);
    }

    // scan the full transaction bytes and return the first two output
    // values (in satoshis) and addresses (in binary)
    function getFirstTwoOutputs(bytes txBytes) internal pure
             returns (uint, bytes20, uint, bytes20)
    {
        uint pos;
        uint[] memory input_script_lens;
        uint[] memory output_script_lens;
        uint[] memory script_starts;
        uint[] memory output_values;
        bytes20[] memory output_public_key_hashes = new bytes20[](2);

        pos = 4;  // skip version

        (, input_script_lens, pos) = scanInputs(txBytes, pos, 0);

        (output_values, script_starts, output_script_lens, pos) = scanOutputs(txBytes, pos, 2);

        for (uint i = 0; i < 2; i++) {
            bytes20 pkhash = parseP2PKHOutputScript(txBytes, script_starts[i], output_script_lens[i]);
            output_public_key_hashes[i] = pkhash;
        }

        return (output_values[0], output_public_key_hashes[0],
                output_values[1], output_public_key_hashes[1]);
    }

    function getFirstInputPubKey(bytes txBytes) private pure
             returns (bytes32, bool)
    {
        uint pos;
        uint[] memory input_script_lens;
        // The line above fires a warning because the variable hasn't been used.
        // It's probably NOT a good idea to comment it until the function is more or less finished because the warning could be useful for debugging.

        pos = 4;  // skip version

        (, pos) = parseVarInt(txBytes, pos);
        return getInputPubKey(txBytes, pos);
    }

    function getInputPubKey(bytes txBytes, uint pos) private pure
             returns (bytes32, bool)
    {
        pos += 36;  // skip outpoint
        (, pos) = parseVarInt(txBytes, pos);
        bytes32 pubKey;
        bool odd;
        (, pubKey, odd, pos) = parseScriptSig(txBytes, pos);
        return (pubKey, odd);
    }

    // Check whether `btcAddress` is in the transaction outputs *and*
    // whether *at least* `value` has been sent to it.
    function checkValueSent(bytes txBytes, bytes20 btcAddress, uint value) private pure
             returns (bool)
    {
        uint pos = 4;  // skip version
        (,, pos) = scanInputs(txBytes, pos, 0);  // find end of inputs

        // scan *all* the outputs and find where they are
        uint[] memory output_values;
        uint[] memory script_starts;
        uint[] memory output_script_lens;
        (output_values, script_starts, output_script_lens,) = scanOutputs(txBytes, pos, 0);

        // look at each output and check whether it at least value to btcAddress
        for (uint i = 0; i < output_values.length; i++) {
            bytes20 pkhash = parseOutputScript(txBytes, script_starts[i], output_script_lens[i]);
            if (pkhash == btcAddress && output_values[i] >= value) {
                return true;
            }
        }
    }
    // scan the inputs and find the script lengths.
    // return an array of script lengths and the end position
    // of the inputs.
    // takes a 'stop' argument which sets the maximum number of
    // outputs to scan through. stop=0 => scan all.
    function scanInputs(bytes txBytes, uint pos, uint stop) private pure
             returns (uint[], uint[], uint)
    {
        uint n_inputs;
        uint halt;
        uint script_len;

        (n_inputs, pos) = parseVarInt(txBytes, pos);

        if (stop == 0 || stop > n_inputs) {
            halt = n_inputs;
        } else {
            halt = stop;
        }

        uint[] memory script_starts = new uint[](halt);
        uint[] memory script_lens = new uint[](halt);

        for (uint256 i = 0; i < halt; i++) {
            script_starts[i] = pos;
            pos += 36;  // skip outpoint
            (script_len, pos) = parseVarInt(txBytes, pos);
            script_lens[i] = script_len;
            pos += script_len + 4;  // skip sig_script, seq
        }

        return (script_starts, script_lens, pos);
    }
    // similar to scanInputs, but consumes less gas since it doesn't store the inputs
    // also returns position of coinbase tx for later use
    function skipInputsAndGetScriptPos(bytes txBytes, uint pos, uint stop) private pure
             returns (uint, uint)
    {
        uint script_pos;

        uint n_inputs;
        uint halt;
        uint script_len;

        (n_inputs, pos) = parseVarInt(txBytes, pos);

        if (stop == 0 || stop > n_inputs) {
            halt = n_inputs;
        } else {
            halt = stop;
        }

        for (uint256 i = 0; i < halt; i++) {
            pos += 36;  // skip outpoint
            (script_len, pos) = parseVarInt(txBytes, pos);
            if (i == 0)
                script_pos = pos; // first input script begins where first script length ends
            // (script_len, pos) = (1, 0);
            pos += script_len + 4;  // skip sig_script, seq
        }

        return (pos, script_pos);
    }
    // scan the outputs and find the values and script lengths.
    // return array of values, array of script lengths and the
    // end position of the outputs.
    // takes a 'stop' argument which sets the maximum number of
    // outputs to scan through. stop=0 => scan all.
    function scanOutputs(bytes txBytes, uint pos, uint stop) private pure
             returns (uint[], uint[], uint[], uint)
    {
        uint n_outputs;
        uint halt;
        uint script_len;

        (n_outputs, pos) = parseVarInt(txBytes, pos);

        if (stop == 0 || stop > n_outputs) {
            halt = n_outputs;
        } else {
            halt = stop;
        }

        uint[] memory script_starts = new uint[](halt);
        uint[] memory script_lens = new uint[](halt);
        uint[] memory output_values = new uint[](halt);

        for (uint256 i = 0; i < halt; i++) {
            output_values[i] = getBytesLE(txBytes, pos, 64);
            pos += 8;

            (script_len, pos) = parseVarInt(txBytes, pos);
            script_starts[i] = pos;
            script_lens[i] = script_len;
            pos += script_len;
        }

        return (output_values, script_starts, script_lens, pos);
    }
    // similar to scanOutputs, but consumes less gas since it doesn't store the outputs
    function skipOutputs(bytes txBytes, uint pos, uint stop) private pure
             returns (uint)
    {
        uint n_outputs;
        uint halt;
        uint script_len;

        (n_outputs, pos) = parseVarInt(txBytes, pos);

        if (stop == 0 || stop > n_outputs) {
            halt = n_outputs;
        } else {
            halt = stop;
        }

        for (uint256 i = 0; i < halt; i++) {
            pos += 8;

            (script_len, pos) = parseVarInt(txBytes, pos);
            pos += script_len;
        }

        return pos;
    }
    // get final position of inputs, outputs and lock time
    // this is a helper function to slice a byte array and hash the inputs, outputs and lock time
    function getSlicePosAndScriptPos(bytes txBytes, uint pos) private pure
             returns (uint slicePos, uint scriptPos)
    {
        (slicePos, scriptPos) = skipInputsAndGetScriptPos(txBytes, pos + 4, 0);
        slicePos = skipOutputs(txBytes, slicePos, 0);
        slicePos += 4; // skip lock time
    }
    // scan a Merkle branch.
    // return array of values and the end position of the sibling hashes.
    // takes a 'stop' argument which sets the maximum number of
    // siblings to scan through. stop=0 => scan all.
    function scanMerkleBranch(bytes txBytes, uint pos, uint stop) private pure
             returns (uint[], uint)
    {
        uint n_siblings;
        uint halt;

        (n_siblings, pos) = parseVarInt(txBytes, pos);

        if (stop == 0 || stop > n_siblings) {
            halt = n_siblings;
        } else {
            halt = stop;
        }

        uint[] memory sibling_values = new uint[](halt);

        for (uint256 i = 0; i < halt; i++) {
            sibling_values[i] = flip32Bytes(sliceBytes32Int(txBytes, pos));
            pos += 32;
        }

        return (sibling_values, pos);
    }
    // Slice 20 contiguous bytes from bytes `data`, starting at `start`
    function sliceBytes20(bytes data, uint start) private pure returns (bytes20) {
        uint160 slice = 0;
        // FIXME: With solc v0.4.24 and optimizations enabled
        // using uint160 for index i will generate an error
        // "Error: VM Exception while processing transaction: Error: redPow(normalNum)"
        for (uint256 i = 0; i < 20; i++) {
            slice += uint160(data[i + start]) << (8 * (19 - i));
        }
        return bytes20(slice);
    }
    // Slice 32 contiguous bytes from bytes `data`, starting at `start`
    function sliceBytes32Int(bytes data, uint start) private pure returns (uint slice) {
        for (uint i = 0; i < 32; i++) {
            if (i + start < data.length) {
                slice += uint(data[i + start]) << (8 * (31 - i));
            }
        }
    }

    // @dev returns a portion of a given byte array specified by its starting and ending points
    // Should be private, made internal for testing
    // Breaks underscore naming convention for parameters because it raises a compiler error
    // if `offset` is changed to `_offset`.
    //
    // @param _rawBytes - array to be sliced
    // @param offset - first byte of sliced array
    // @param _endIndex - last byte of sliced array
    function sliceArray(bytes memory _rawBytes, uint offset, uint _endIndex) internal view returns (bytes) {
        uint len = _endIndex - offset;
        bytes memory result = new bytes(len);
        assembly {
            // Call precompiled contract to copy data
            if iszero(staticcall(gas, 0x04, add(add(_rawBytes, 0x20), offset), len, add(result, 0x20), len)) {
                revert(0, 0)
            }
        }
        return result;
    }
    // returns true if the bytes located in txBytes by pos and
    // script_len represent a P2PKH script
    function isP2PKH(bytes txBytes, uint pos, uint script_len) private pure returns (bool) {
        return (script_len == 25)           // 20 byte pubkeyhash + 5 bytes of script
            && (txBytes[pos] == 0x76)       // OP_DUP
            && (txBytes[pos + 1] == 0xa9)   // OP_HASH160
            && (txBytes[pos + 2] == 0x14)   // bytes to push
            && (txBytes[pos + 23] == 0x88)  // OP_EQUALVERIFY
            && (txBytes[pos + 24] == 0xac); // OP_CHECKSIG
    }
    // returns true if the bytes located in txBytes by pos and
    // script_len represent a P2SH script
    function isP2SH(bytes txBytes, uint pos, uint script_len) private pure returns (bool) {
        return (script_len == 23)           // 20 byte scripthash + 3 bytes of script
            && (txBytes[pos + 0] == 0xa9)   // OP_HASH160
            && (txBytes[pos + 1] == 0x14)   // bytes to push
            && (txBytes[pos + 22] == 0x87); // OP_EQUAL
    }
    // Get the pubkeyhash / scripthash from an output script. Assumes
    // pay-to-pubkey-hash (P2PKH) or pay-to-script-hash (P2SH) outputs.
    // Returns the pubkeyhash/ scripthash, or zero if unknown output.
    function parseOutputScript(bytes txBytes, uint pos, uint script_len) private pure
             returns (bytes20)
    {
        if (isP2PKH(txBytes, pos, script_len)) {
            return sliceBytes20(txBytes, pos + 3);
        } else if (isP2SH(txBytes, pos, script_len)) {
            return sliceBytes20(txBytes, pos + 2);
        } else {
            return;
        }
    }

    // Get the pubkeyhash from an output script. Assumes
    // pay-to-pubkey-hash (P2PKH) outputs.
    // Returns the pubkeyhash, or zero if unknown output.
    function parseP2PKHOutputScript(bytes txBytes, uint pos, uint script_len) private pure
             returns (bytes20)
    {
        if (isP2PKH(txBytes, pos, script_len)) {
            return sliceBytes20(txBytes, pos + 3);
        } else {
            return;
        }
    }


    // Parse a P2PKH scriptSig
    function parseScriptSig(bytes txBytes, uint pos) private pure
             returns (bytes, bytes32, bool, uint)
    {
        bytes memory sig;
        bytes32 pubKey;
        bool odd;
        (sig, pos) = parseSignature(txBytes, pos);
        (pubKey, odd, pos) = parsePubKey(txBytes, pos);
        return (sig, pubKey, odd, pos);
    }

    // Extract a signature
    function parseSignature(bytes txBytes, uint pos) private pure
             returns (bytes, uint)
    {
        uint8 op;
        bytes memory sig;
        (op, pos) = getOpcode(txBytes, pos);
        require(op >= 9 && op <= 73);
        require(uint8(txBytes[pos]) == 0x30);
        //FIXME: Copy signature
        pos += op;
        return (sig, pos);
    }

    // Extract public key
    function parsePubKey(bytes txBytes, uint pos) private pure
             returns (bytes32, bool, uint)
    {
        uint8 op;
        (op, pos) = getOpcode(txBytes, pos);
        //FIXME: Add support for uncompressed public keys
        require(op == 33);
        bytes32 pubKey;
        bool odd = txBytes[pos] == 0x03;
        pos += 1;
        assembly {
            pubKey := mload(add(add(txBytes, 0x20), pos))
        }
        pos += 32;
        return (pubKey, odd, pos);
    }

    // Read next opcode from script
    function getOpcode(bytes txBytes, uint pos) private pure
             returns (uint8, uint)
    {
        return (uint8(txBytes[pos]), pos + 1);
    }

    function expmod(uint256 base, uint256 e, uint256 m) internal returns (uint256 o) {
        assembly {
            // pointer to free memory
            let p := mload(0x40)
            mstore(p, 0x20)             // Length of Base
            mstore(add(p, 0x20), 0x20)  // Length of Exponent
            mstore(add(p, 0x40), 0x20)  // Length of Modulus
            mstore(add(p, 0x60), base)  // Base
            mstore(add(p, 0x80), e)     // Exponent
            mstore(add(p, 0xa0), m)     // Modulus
            // call modexp precompile!
            if iszero(call(not(0), 0x05, 0, p, 0xc0, p, 0x20)) {
                revert(0, 0)
            }
            // data
            o := mload(p)
        }
    }

    function pub2address(uint x, bool odd) internal returns (address) {
        // First, uncompress pub key
        uint yy = mulmod(x, x, p);
        yy = mulmod(yy, x, p);
        yy = addmod(yy, 7, p);
        uint y = expmod(yy, q, p);
        if (((y & 1) == 1) != odd) {
          y = p - y;
        }
        require(yy == mulmod(y, y, p));
        // Now, with uncompressed x and y, create the address
        return address(keccak256(abi.encodePacked(x, y)));
    }

    // Gets the public key hash given a public key
    function pub2PubKeyHash(bytes32 pub, bool odd) internal pure returns (bytes20) {
        byte firstByte = odd ? byte(0x03) : byte(0x02);
        return ripemd160(abi.encodePacked(sha256(abi.encodePacked(firstByte, pub))));
    }

    // @dev - convert an unsigned integer from little-endian to big-endian representation
    //
    // @param _input - little-endian value
    // @return - input value in big-endian format
    function flip32Bytes(uint _input) internal pure returns (uint result) {
        assembly {
            let pos := mload(0x40)
            for { let i := 0 } lt(i, 32) { i := add(i, 1) } {
                mstore8(add(pos, i), byte(sub(31, i), _input))
            }
            result := mload(pos)
        }
    }
    // helpers for flip32Bytes
    struct UintWrapper {
        uint value;
    }

    function ptr(UintWrapper memory uw) private pure returns (uint addr) {
        assembly {
            addr := uw
        }
    }

    function parseAuxPoW(bytes rawBytes, uint pos, uint len) internal view
             returns (AuxPoW memory auxpow)
    {
        // we need to traverse the bytes with a pointer because some fields are of variable length
        pos += 80; // skip non-AuxPoW header
        // auxpow.firstBytes = sliceBytes32Int(rawBytes, pos);
        uint slicePos;
        uint inputScriptPos;
        (slicePos, inputScriptPos) = getSlicePosAndScriptPos(rawBytes, pos);
        auxpow.txHash = dblShaFlipMem(rawBytes, pos, slicePos - pos);
        pos = slicePos;
        auxpow.scryptHash = sliceBytes32Int(rawBytes, pos);
        pos += 32;
        (auxpow.parentMerkleProof, pos) = scanMerkleBranch(rawBytes, pos, 0);
        auxpow.coinbaseTxIndex = getBytesLE(rawBytes, pos, 32);
        pos += 4;
        (auxpow.chainMerkleProof, pos) = scanMerkleBranch(rawBytes, pos, 0);
        auxpow.dogeHashIndex = getBytesLE(rawBytes, pos, 32);
        pos += 40; // skip hash that was just read, parent version and prev block
        auxpow.parentMerkleRoot = sliceBytes32Int(rawBytes, pos);
        pos += 40; // skip root that was just read, parent block timestamp and bits
        auxpow.parentNonce = getBytesLE(rawBytes, pos, 32);
        uint coinbaseMerkleRootPosition;
        (auxpow.coinbaseMerkleRoot, coinbaseMerkleRootPosition, auxpow.coinbaseMerkleRootCode) = findCoinbaseMerkleRoot(rawBytes);
        if (coinbaseMerkleRootPosition - inputScriptPos > 20 && auxpow.coinbaseMerkleRootCode == 1) {
            // if it was found once and only once but not in the first 20 bytes, return this error code
            auxpow.coinbaseMerkleRootCode = ERR_NOT_IN_FIRST_20;
        }
    }

    // @dev - looks for {0xfa, 0xbe, 'm', 'm'} byte sequence
    // returns the following 32 bytes if it appears once and only once,
    // 0 otherwise
    // also returns the position where the bytes first appear
    function findCoinbaseMerkleRoot(bytes rawBytes) private pure
             returns (uint, uint, uint)
    {
        uint position;
        bool found = false;

        for (uint i = 0; i < rawBytes.length; ++i) {
            if (rawBytes[i] == 0xfa && rawBytes[i+1] == 0xbe && rawBytes[i+2] == 0x6d && rawBytes[i+3] == 0x6d) {
                if (found) { // found twice
                    return (0, position - 4, ERR_FOUND_TWICE);
                } else {
                    found = true;
                    position = i + 4;
                }
            }
        }

        if (!found) { // no merge mining header
            return (0, position - 4, ERR_NO_MERGE_HEADER);
        } else {
            return (sliceBytes32Int(rawBytes, position), position - 4, 1);
        }
    }

    // @dev - Evaluate the merkle root
    //
    // Given an array of hashes it calculates the
    // root of the merkle tree.
    //
    // @return root of merkle tree
    function makeMerkle(bytes32[] hashes2) external pure returns (bytes32) {
        bytes32[] memory hashes = hashes2;
        uint length = hashes.length;
        if (length == 1) return hashes[0];
        require(length > 0);
        uint i;
        uint j;
        uint k;
        k = 0;
        while (length > 1) {
            k = 0;
            for (i = 0; i < length; i += 2) {
                j = i+1<length ? i+1 : length-1;
                hashes[k] = bytes32(concatHash(uint(hashes[i]), uint(hashes[j])));
                k += 1;
            }
            length = k;
        }
        return hashes[0];
    }

    // @dev - For a valid proof, returns the root of the Merkle tree.
    //
    // @param _txHash - transaction hash
    // @param _txIndex - transaction's index within the block it's assumed to be in
    // @param _siblings - transaction's Merkle siblings
    // @return - Merkle tree root of the block the transaction belongs to if the proof is valid,
    // garbage if it's invalid
    function computeMerkle(uint _txHash, uint _txIndex, uint[] _siblings) internal pure returns (uint) {
        uint resultHash = _txHash;
        uint i = 0;
        while (i < _siblings.length) {
            uint proofHex = _siblings[i];

            uint sideOfSiblings = _txIndex % 2;  // 0 means _siblings is on the right; 1 means left

            uint left;
            uint right;
            if (sideOfSiblings == 1) {
                left = proofHex;
                right = resultHash;
            } else if (sideOfSiblings == 0) {
                left = resultHash;
                right = proofHex;
            }

            resultHash = concatHash(left, right);

            _txIndex /= 2;
            i += 1;
        }

        return resultHash;
    }

    // @dev - calculates the Merkle root of a tree containing Litecoin transactions
    // in order to prove that `ap`'s coinbase tx is in that Litecoin block.
    //
    // @param _ap - AuxPoW information
    // @return - Merkle root of Litecoin block that the Dogecoin block
    // with this info was mined in if AuxPoW Merkle proof is correct,
    // garbage otherwise
    function computeParentMerkle(AuxPoW _ap) internal pure returns (uint) {
        return flip32Bytes(computeMerkle(_ap.txHash,
                                         _ap.coinbaseTxIndex,
                                         _ap.parentMerkleProof));
    }

    // @dev - calculates the Merkle root of a tree containing auxiliary block hashes
    // in order to prove that the Dogecoin block identified by _blockHash
    // was merge-mined in a Litecoin block.
    //
    // @param _blockHash - SHA-256 hash of a certain Dogecoin block
    // @param _ap - AuxPoW information corresponding to said block
    // @return - Merkle root of auxiliary chain tree
    // if AuxPoW Merkle proof is correct, garbage otherwise
    function computeChainMerkle(uint _blockHash, AuxPoW _ap) internal pure returns (uint) {
        return computeMerkle(_blockHash,
                             _ap.dogeHashIndex,
                             _ap.chainMerkleProof);
    }

    // @dev - Helper function for Merkle root calculation.
    // Given two sibling nodes in a Merkle tree, calculate their parent.
    // Concatenates hashes `_tx1` and `_tx2`, then hashes the result.
    //
    // @param _tx1 - Merkle node (either root or internal node)
    // @param _tx2 - Merkle node (either root or internal node), has to be `_tx1`'s sibling
    // @return - `_tx1` and `_tx2`'s parent, i.e. the result of concatenating them,
    // hashing that twice and flipping the bytes.
    function concatHash(uint _tx1, uint _tx2) internal pure returns (uint) {
        return flip32Bytes(uint(sha256(abi.encodePacked(sha256(abi.encodePacked(flip32Bytes(_tx1), flip32Bytes(_tx2)))))));
    }

    // @dev - checks if a merge-mined block's Merkle proofs are correct,
    // i.e. Doge block hash is in coinbase Merkle tree
    // and coinbase transaction is in parent Merkle tree.
    //
    // @param _blockHash - SHA-256 hash of the block whose Merkle proofs are being checked
    // @param _ap - AuxPoW struct corresponding to the block
    // @return 1 if block was merge-mined and coinbase index, chain Merkle root and Merkle proofs are correct,
    // respective error code otherwise
    function checkAuxPoW(uint _blockHash, AuxPoW _ap) internal pure returns (uint) {
        if (_ap.coinbaseTxIndex != 0) {
            return ERR_COINBASE_INDEX;
        }

        if (_ap.coinbaseMerkleRootCode != 1) {
            return _ap.coinbaseMerkleRootCode;
        }

        if (computeChainMerkle(_blockHash, _ap) != _ap.coinbaseMerkleRoot) {
            return ERR_CHAIN_MERKLE;
        }

        if (computeParentMerkle(_ap) != _ap.parentMerkleRoot) {
            return ERR_PARENT_MERKLE;
        }

        return 1;
    }

    function sha256mem(bytes memory _rawBytes, uint offset, uint len) internal view returns (bytes32 result) {
        assembly {
            // Call sha256 precompiled contract (located in address 0x02) to copy data.
            // Assign to ptr the next available memory position (stored in memory position 0x40).
            let ptr := mload(0x40)
            if iszero(staticcall(gas, 0x02, add(add(_rawBytes, 0x20), offset), len, ptr, 0x20)) {
                revert(0, 0)
            }
            result := mload(ptr)
        }
    }

    // @dev - Bitcoin-way of hashing
    // @param _dataBytes - raw data to be hashed
    // @return - result of applying SHA-256 twice to raw data and then flipping the bytes
    function dblShaFlip(bytes _dataBytes) internal pure returns (uint) {
        return flip32Bytes(uint(sha256(abi.encodePacked(sha256(abi.encodePacked(_dataBytes))))));
    }

    // @dev - Bitcoin-way of hashing
    // @param _dataBytes - raw data to be hashed
    // @return - result of applying SHA-256 twice to raw data and then flipping the bytes
    function dblShaFlipMem(bytes memory _rawBytes, uint offset, uint len) internal view returns (uint) {
        return flip32Bytes(uint(sha256(abi.encodePacked(sha256mem(_rawBytes, offset, len)))));
    }

    // @dev – Read a bytes32 from an offset in the byte array
    function readBytes32(bytes data, uint offset) internal pure returns (bytes32) {
        bytes32 result;
        assembly {
            result := mload(add(add(data, 0x20), offset))
        }
        return result;
    }

    // @dev – Read an uint32 from an offset in the byte array
    function readUint32(bytes data, uint offset) internal pure returns (uint32) {
        uint32 result;
        assembly {
            let word := mload(add(add(data, 0x20), offset))
            result := add(byte(3, word),
                add(mul(byte(2, word), 0x100),
                    add(mul(byte(1, word), 0x10000),
                        mul(byte(0, word), 0x1000000))))
        }
        return result;
    }

    // @dev - Bitcoin-way of computing the target from the 'bits' field of a block header
    // based on http://www.righto.com/2014/02/bitcoin-mining-hard-way-algorithms.html//ref3
    //
    // @param _bits - difficulty in bits format
    // @return - difficulty in target format
    function targetFromBits(uint32 _bits) internal pure returns (uint) {
        uint exp = _bits / 0x1000000;  // 2**24
        uint mant = _bits & 0xffffff;
        return mant * 256**(exp - 3);
    }

    uint constant DOGECOIN_DIFFICULTY_ONE = 0xFFFFF * 256**(0x1e - 3);

    // @dev - Calculate dogecoin difficulty from target
    // https://en.bitcoin.it/wiki/Difficulty
    // Min difficulty for bitcoin is 0x1d00ffff
    // Min difficulty for dogecoin is 0x1e0fffff
    function targetToDiff(uint target) internal pure returns (uint) {
        return DOGECOIN_DIFFICULTY_ONE / target;
    }

    // @dev - Parse an array of bytes32
    function parseBytes32Array(bytes data) external pure returns (bytes32[]) {
        require(data.length % 32 == 0);
        uint count = data.length / 32;
        bytes32[] memory hashes = new bytes32[](count);
        for (uint i=0; i<count; ++i) {
            hashes[i] = readBytes32(data, 32*i);
        }
        return hashes;
    }

    // 0x00 version
    // 0x04 prev block hash
    // 0x24 merkle root
    // 0x44 timestamp
    // 0x48 bits
    // 0x4c nonce

    // @dev - extract version field from a raw Dogecoin block header
    //
    // @param _blockHeader - Dogecoin block header bytes
    // @param pos - where to start reading version from
    // @return - block's version in big endian format
    function getVersion(bytes memory _blockHeader, uint pos) internal pure returns (uint32 version) {
        assembly {
            let word := mload(add(add(_blockHeader, 0x4), pos))
            version := add(byte(24, word),
                add(mul(byte(25, word), 0x100),
                    add(mul(byte(26, word), 0x10000),
                        mul(byte(27, word), 0x1000000))))
        }
    }

    // @dev - extract previous block field from a raw Dogecoin block header
    //
    // @param _blockHeader - Dogecoin block header bytes
    // @param pos - where to start reading hash from
    // @return - hash of block's parent in big endian format
    function getHashPrevBlock(bytes memory _blockHeader, uint pos) internal pure returns (uint) {
        uint hashPrevBlock;
        assembly {
            hashPrevBlock := mload(add(add(_blockHeader, 0x24), pos))
        }
        return flip32Bytes(hashPrevBlock);
    }

    // @dev - extract Merkle root field from a raw Dogecoin block header
    //
    // @param _blockHeader - Dogecoin block header bytes
    // @param pos - where to start reading root from
    // @return - block's Merkle root in big endian format
    function getHeaderMerkleRoot(bytes _blockHeader, uint pos) public pure returns (uint) {
        uint merkle;
        assembly {
            merkle := mload(add(add(_blockHeader, 0x44), pos))
        }
        return flip32Bytes(merkle);
    }

    // @dev - extract bits field from a raw Dogecoin block header
    //
    // @param _blockHeader - Dogecoin block header bytes
    // @param pos - where to start reading bits from
    // @return - block's difficulty in bits format, also big-endian
    function getBits(bytes memory _blockHeader, uint pos) internal pure returns (uint32 bits) {
        assembly {
            let word := mload(add(add(_blockHeader, 0x50), pos))
            bits := add(byte(24, word),
                add(mul(byte(25, word), 0x100),
                    add(mul(byte(26, word), 0x10000),
                        mul(byte(27, word), 0x1000000))))
        }
    }

    // @dev - extract timestamp field from a raw Dogecoin block header
    //
    // @param _blockHeader - Dogecoin block header bytes
    // @param pos - where to start reading bits from
    // @return - block's timestamp in big-endian format
    function getTimestamp(bytes memory _blockHeader, uint pos) internal pure returns (uint32 time) {
        assembly {
            let word := mload(add(add(_blockHeader, 0x4c), pos))
            time := add(byte(24, word),
                add(mul(byte(25, word), 0x100),
                    add(mul(byte(26, word), 0x10000),
                        mul(byte(27, word), 0x1000000))))
        }
    }

    // @dev - converts raw bytes representation of a Dogecoin block header to struct representation
    //
    // @param _rawBytes - first 80 bytes of a block header
    // @return - exact same header information in BlockHeader struct form
    function parseHeaderBytes(bytes _rawBytes, uint pos) internal view returns (BlockHeader bh) {
        bh.version = getVersion(_rawBytes, pos);
        bh.time = getTimestamp(_rawBytes, pos);
        bh.bits = getBits(_rawBytes, pos);
        bh.blockHash = dblShaFlipMem(_rawBytes, pos, 80);
        bh.prevBlock = getHashPrevBlock(_rawBytes, pos);
        bh.merkleRoot = getHeaderMerkleRoot(_rawBytes, pos);
    }

    uint32 constant VERSION_AUXPOW = (1 << 8);

    // @dev - Converts a bytes of size 4 to uint32,
    // e.g. for input [0x01, 0x02, 0x03 0x04] returns 0x01020304
    function bytesToUint32Flipped(bytes input, uint pos) internal pure returns (uint32 result) {
        result = uint32(input[pos]) + uint32(input[pos + 1])*(2**8) + uint32(input[pos + 2])*(2**16) + uint32(input[pos + 3])*(2**24);
    }

    // @dev - checks version to determine if a block has merge mining information
    function isMergeMined(bytes _rawBytes, uint pos) internal pure returns (bool) {
        return bytesToUint32Flipped(_rawBytes, pos) & VERSION_AUXPOW != 0;
    }

    // @dev - checks version to determine if a block has merge mining information
    function isMergeMined(BlockHeader _blockHeader) internal pure returns (bool) {
        return _blockHeader.version & VERSION_AUXPOW != 0;
    }

    // @dev - Verify block header
    // @param _blockHeaderBytes array of bytes with the block header
    // @param _pos starting position of the block header
    // @param _len length of the block header
    // @param _proposedBlockScryptash proposed block scrypt hash
    // @return - [ErrorCode, BlockSha256Hash, BlockScryptHash, IsMergeMined] 
    function verifyBlockHeader(bytes _blockHeaderBytes, uint _pos, uint _len, uint _proposedBlockScryptash) external view returns (uint, uint, uint, bool) {
        BlockHeader memory blockHeader = parseHeaderBytes(_blockHeaderBytes, _pos);
        uint blockSha256Hash = blockHeader.blockHash;
        if (isMergeMined(blockHeader)) {
            AuxPoW memory ap = parseAuxPoW(_blockHeaderBytes, _pos, _len);
            if (flip32Bytes(ap.scryptHash) > targetFromBits(blockHeader.bits)) {
                return (ERR_PROOF_OF_WORK, blockHeader.blockHash, ap.scryptHash, true);
            }
            uint auxPoWCode = checkAuxPoW(blockSha256Hash, ap);
            if (auxPoWCode != 1) {
                return (auxPoWCode, blockHeader.blockHash, ap.scryptHash, true);
            }
            return (0, blockHeader.blockHash, ap.scryptHash, true);
        } else {
            if (flip32Bytes(_proposedBlockScryptash) > targetFromBits(blockHeader.bits)) {
                return (ERR_PROOF_OF_WORK, blockHeader.blockHash, _proposedBlockScryptash, false);
            }
            return (0, blockHeader.blockHash, _proposedBlockScryptash, false);
        }
    }

    // @dev - Calculate difficulty from block compact representation (bits)
    function diffFromBits(uint32 bits) external pure returns (uint) {
        return targetToDiff(targetFromBits(bits));
    }

    // For verifying Dogecoin difficulty
    uint constant DIFFICULTY_ADJUSTMENT_INTERVAL = 1;  // Bitcoin adjusts every block
    uint constant TARGET_TIMESPAN =  60;  // 1 minute
    uint constant TARGET_TIMESPAN_DIV_4 = TARGET_TIMESPAN / 4;
    uint constant TARGET_TIMESPAN_MUL_4 = TARGET_TIMESPAN * 4;
    uint constant UNROUNDED_MAX_TARGET = 2**224 - 1;  // different from (2**16-1)*2**208 http =//bitcoin.stackexchange.com/questions/13803/how/ exactly-was-the-original-coefficient-for-difficulty-determined
    uint constant POW_LIMIT = 0x00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    // @dev - Implementation of DigiShield, almost directly translated from
    // C++ implementation of Dogecoin. See function CalculateDogecoinNextWorkRequired
    // on dogecoin/src/dogecoin.cpp for more details.
    // Calculates the next block's difficulty based on the current block's elapsed time
    // and the desired mining time for a block, which is 60 seconds after block 145k.
    //
    // @param _actualTimespan - time elapsed from previous block creation til current block creation;
    // i.e., how much time it took to mine the current block
    // @param _bits - previous block header difficulty (in bits)
    // @return - expected difficulty for the next block
    function calculateDigishieldDifficulty(int64 _actualTimespan, uint32 _bits) external pure returns (uint32 result) {
        int64 retargetTimespan = int64(TARGET_TIMESPAN);
        int64 nModulatedTimespan = int64(_actualTimespan);

        nModulatedTimespan = retargetTimespan + int64(nModulatedTimespan - retargetTimespan) / int64(8); //amplitude filter
        int64 nMinTimespan = retargetTimespan - (int64(retargetTimespan) / int64(4));
        int64 nMaxTimespan = retargetTimespan + (int64(retargetTimespan) / int64(2));

        // Limit adjustment step
        if (nModulatedTimespan < nMinTimespan) {
            nModulatedTimespan = nMinTimespan;
        } else if (nModulatedTimespan > nMaxTimespan) {
            nModulatedTimespan = nMaxTimespan;
        }

        // Retarget
        uint bnNew = targetFromBits(_bits);
        bnNew = bnNew * uint(nModulatedTimespan);
        bnNew = uint(bnNew) / uint(retargetTimespan);

        if (bnNew > POW_LIMIT) {
            bnNew = POW_LIMIT;
        }

        return toCompactBits(bnNew);
    }

    // @dev - shift information to the right by a specified number of bits
    //
    // @param _val - value to be shifted
    // @param _shift - number of bits to shift
    // @return - `_val` shifted `_shift` bits to the right, i.e. divided by 2**`_shift`
    function shiftRight(uint _val, uint _shift) private pure returns (uint) {
        return _val / uint(2)**_shift;
    }

    // @dev - shift information to the left by a specified number of bits
    //
    // @param _val - value to be shifted
    // @param _shift - number of bits to shift
    // @return - `_val` shifted `_shift` bits to the left, i.e. multiplied by 2**`_shift`
    function shiftLeft(uint _val, uint _shift) private pure returns (uint) {
        return _val * uint(2)**_shift;
    }

    // @dev - get the number of bits required to represent a given integer value without losing information
    //
    // @param _val - unsigned integer value
    // @return - given value's bit length
    function bitLen(uint _val) private pure returns (uint length) {
        uint int_type = _val;
        while (int_type > 0) {
            int_type = shiftRight(int_type, 1);
            length += 1;
        }
    }

    // @dev - Convert uint256 to compact encoding
    // based on https://github.com/petertodd/python-bitcoinlib/blob/2a5dda45b557515fb12a0a18e5dd48d2f5cd13c2/bitcoin/core/serialize.py
    // Analogous to arith_uint256::GetCompact from C++ implementation
    //
    // @param _val - difficulty in target format
    // @return - difficulty in bits format
    function toCompactBits(uint _val) private pure returns (uint32) {
        uint nbytes = uint (shiftRight((bitLen(_val) + 7), 3));
        uint32 compact = 0;
        if (nbytes <= 3) {
            compact = uint32 (shiftLeft((_val & 0xFFFFFF), 8 * (3 - nbytes)));
        } else {
            compact = uint32 (shiftRight(_val, 8 * (nbytes - 3)));
            compact = uint32 (compact & 0xFFFFFF);
        }

        // If the sign bit (0x00800000) is set, divide the mantissa by 256 and
        // increase the exponent to get an encoding without it set.
        if ((compact & 0x00800000) > 0) {
            compact = uint32(shiftRight(compact, 8));
            nbytes += 1;
        }

        return compact | uint32(shiftLeft(nbytes, 24));
    }
}

pragma solidity ^0.4.23;


/**
 * @title Eliptic curve signature operations
 *
 * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
 *
 * TODO Remove this library once solidity supports passing a signature to ecrecover.
 * See https://github.com/ethereum/solidity/issues/864
 *
 */

library ECRecovery {

  /**
   * @dev Recover signer address from a message by using their signature
   * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
   * @param sig bytes signature, the signature is generated using web3.eth.sign()
   */
  function recover(bytes32 hash, bytes sig)
    internal
    pure
    returns (address)
  {
    bytes32 r;
    bytes32 s;
    uint8 v;

    // Check the signature length
    if (sig.length != 65) {
      return (address(0));
    }

    // Divide the signature in r, s and v variables
    // ecrecover takes the signature parameters, and the only way to get them
    // currently is to use assembly.
    // solium-disable-next-line security/no-inline-assembly
    assembly {
      v := byte(0, mload(add(sig, 32))) // 0
      r := mload(add(sig, 33)) // 1
      s := mload(add(sig, 65)) // 33
    }

    // Version of signature should be 27 or 28, but 0 and 1 are also possible versions
    if (v < 27) {
      v += 27;
    }

    // If the version is correct return the signer address
    if (v != 27 && v != 28) {
      return (address(0));
    } else {
      // solium-disable-next-line arg-overflow
      return ecrecover(hash, v, r, s);
    }
  }

  /**
   * toEthSignedMessageHash
   * @dev prefix a bytes32 value with "\x19Ethereum Signed Message:"
   * @dev and hash the result
   */
  function toEthSignedMessageHash(bytes32 hash)
    internal
    pure
    returns (bytes32)
  {
    // 32 is the length in bytes of hash,
    // enforced by the type signature above
    return keccak256(
      abi.encodePacked("\x19Ethereum Signed Message:\n32",
      hash)
    );
  }
}

contract DogeToken is HumanStandardToken(0, "DogeToken", 8, "DOGETOKEN"), TransactionProcessor {

    // Lock constants
    uint public constant MIN_LOCK_VALUE = 300000000; // 3 doges
    uint public constant OPERATOR_LOCK_FEE = 10; // 1 = 0.1%
    uint public constant OPERATOR_MIN_LOCK_FEE = 100000000; // 1 doge
    uint public constant SUPERBLOCK_SUBMITTER_LOCK_FEE = 10; // 1 = 0.1%
    uint public constant SUPERBLOCK_SUBMITTER_MIN_LOCK_FEE = 100000000; // 1 doge

    // Unlock constants
    uint public constant MIN_UNLOCK_VALUE = 300000000; // 3 doges
    uint public constant OPERATOR_UNLOCK_FEE = 10; // 1 = 0.1%
    uint public constant OPERATOR_MIN_UNLOCK_FEE = 100000000; // 1 doge
    uint constant DOGE_TX_BASE_FEE = 50000000; // 0.5 doge
    uint constant DOGE_TX_FEE_PER_INPUT = 100000000; // 1 doge

    // Error codes
    uint constant ERR_OPERATOR_SIGNATURE = 60010;
    uint constant ERR_OPERATOR_ALREADY_CREATED = 60015;
    uint constant ERR_OPERATOR_NOT_CREATED_OR_WRONG_SENDER = 60020;
    uint constant ERR_OPERATOR_HAS_BALANCE = 60030;
    uint constant ERR_OPERATOR_WITHDRAWAL_NOT_ENOUGH_BALANCE = 60040;
    uint constant ERR_OPERATOR_WITHDRAWAL_COLLATERAL_WOULD_BE_TOO_LOW = 60050;
    uint constant ERR_PROCESS_OPERATOR_NOT_CREATED = 60060;
    uint constant ERR_PROCESS_TX_ALREADY_PROCESSED = 60070;
    uint constant ERR_UNLOCK_MIN_UNLOCK_VALUE = 60080;
    uint constant ERR_UNLOCK_USER_BALANCE = 60090;
    uint constant ERR_UNLOCK_OPERATOR_NOT_CREATED = 60100;
    uint constant ERR_UNLOCK_OPERATOR_BALANCE = 60110;    
    uint constant ERR_UNLOCK_NO_AVAILABLE_UTXOS = 60120;
    uint constant ERR_UNLOCK_UTXOS_VALUE_LESS_THAN_VALUE_TO_SEND = 60130;
    uint constant ERR_UNLOCK_VALUE_TO_SEND_LESS_THAN_FEE = 60140;
    uint constant ERR_LOCK_MIN_LOCK_VALUE = 60150;

    // Variables sets by constructor
    // Contract to trust for tx inclueded in a doge block verification.
    // Only doge txs relayed from trustedRelayerContract will be accepted.
    address public trustedRelayerContract;
    // Doge-Eth price oracle to trust.
    address public trustedDogeEthPriceOracle;
    // Number of times the operator eth collateral should cover her doge holdings 
    uint8 public collateralRatio;


    // counter for next unlock
    uint32 public unlockIdx;
    // Unlocks the investor has not sent a proof of unlock yet.
    mapping (uint32 => Unlock) public unlocksPendingInvestorProof;
    // Doge-Eth currencies current market price.
    uint public dogeEthPrice;
    // operatorPublicKeyHash to Operator
    mapping (bytes20 => Operator) public operators;
    OperatorKey[] public operatorKeys;

    // Doge transactions that were already processed by processTransaction()
    Set.Data dogeTxHashesAlreadyProcessed;

    event ErrorDogeToken(uint err);
    event NewToken(address indexed user, uint value);
    event UnlockRequest(uint32 id, bytes20 operatorPublicKeyHash);

    // Represents an unlock request
    struct Unlock {
          address from;
          string dogeAddress;
          uint value;
          uint operatorFee;
          uint timestamp;
          // Values are indexes in storage array "utxos"
          uint32[] selectedUtxos;
          uint dogeTxFee;
          bytes20 operatorPublicKeyHash;
    }

    struct Utxo {
          uint value;
          uint txHash;
          uint16 index;
    }

    struct Operator {
        address ethAddress;
        uint dogeAvailableBalance;
        uint dogePendingBalance;
        Utxo[] utxos;
        uint32 nextUnspentUtxoIndex;
        uint ethBalance;
        uint24 operatorKeyIndex;
    }

    struct OperatorKey { 
        bytes20 key; 
        bool deleted;
    }

    constructor (address _trustedRelayerContract, address _trustedDogeEthPriceOracle, uint8 _collateralRatio) public {
        trustedRelayerContract = _trustedRelayerContract;
        trustedDogeEthPriceOracle = _trustedDogeEthPriceOracle;
        collateralRatio = _collateralRatio;
    }

    // Adds an operator
    // @param operatorPublicKeyCompressed operator compressed public key (33 bytes). 
    //                          operatorPublicKeyCompressed[0] = odd (0x02 or 0x03)
    //                          operatorPublicKeyCompressed[1-32] = x
    // @param signature doubleSha256(msg.sender) signed by operator (65 bytes).
    //                  signature[0] = v
    //                  signature[1-32] = r
    //                  signature[33-64] = s
    function addOperator(bytes operatorPublicKeyCompressed, bytes signature) public {
        //log0(bytes32(operatorPublicKeyCompressed.length));
        //log0(bytes32(signature.length));

        // Parse operatorPublicKeyCompressed
        bytes32 operatorPublicKeyX;
        bool operatorPublicKeyOdd;
        operatorPublicKeyOdd = operatorPublicKeyCompressed[0] == 0x03;
        assembly {
            operatorPublicKeyX := mload(add(operatorPublicKeyCompressed, 0x21))
        }
        //log1(operatorPublicKeyX, bytes32(operatorPublicKeyOdd ? 1 : 0));

        // Check the non compressed version of operatorPublicKeyCompressed signed msg.sender hash
        bytes32 signedMessage = sha256(abi.encodePacked(sha256(abi.encodePacked(msg.sender))));
        //log1(bytes20(msg.sender), signedMessage);
        address recoveredAddress = ECRecovery.recover(signedMessage, signature);
        //log1(bytes32(recoveredAddress),
        //     bytes32(DogeTx.pub2address(uint(operatorPublicKeyX), operatorPublicKeyOdd)));                
        if (recoveredAddress != DogeTx.pub2address(uint(operatorPublicKeyX), operatorPublicKeyOdd)) {
            emit ErrorDogeToken(ERR_OPERATOR_SIGNATURE);
            return;
        }
        // Create operator
        bytes20 operatorPublicKeyHash = DogeTx.pub2PubKeyHash(operatorPublicKeyX, operatorPublicKeyOdd);
        //log0(operatorPublicKeyHash);
        Operator storage operator = operators[operatorPublicKeyHash];
        // Check operator does not exists yet
        //log1(bytes20(operator.ethAddress), bytes32((operator.ethAddress == 0) ? 0 : 1));
        if (operator.ethAddress != 0) {
            emit ErrorDogeToken(ERR_OPERATOR_ALREADY_CREATED);
            return;
        }        
        operator.ethAddress = msg.sender;
        operator.operatorKeyIndex = uint24(operatorKeys.length);
        operatorKeys.push(OperatorKey(operatorPublicKeyHash, false));
        
    }

    function deleteOperator(bytes20 operatorPublicKeyHash) public {
        Operator storage operator = operators[operatorPublicKeyHash];
        if (operator.ethAddress != msg.sender) {
            emit ErrorDogeToken(ERR_OPERATOR_NOT_CREATED_OR_WRONG_SENDER);
            return;
        }        
        if (operator.dogeAvailableBalance != 0 || operator.dogePendingBalance != 0 || operator.ethBalance != 0) {
            emit ErrorDogeToken(ERR_OPERATOR_HAS_BALANCE);
            return;
        }        

        OperatorKey storage operatorKey = operatorKeys[operator.operatorKeyIndex]; 
        operatorKey.deleted = true;
        delete operators[operatorPublicKeyHash];
    }

    function getOperatorsLength() public view returns (uint24) {
        return uint24(operatorKeys.length);
    }


    function addOperatorDeposit(bytes20 operatorPublicKeyHash) public payable {
        Operator storage operator = operators[operatorPublicKeyHash];
        if (operator.ethAddress != msg.sender) {
            emit ErrorDogeToken(ERR_OPERATOR_NOT_CREATED_OR_WRONG_SENDER);
            return;
        }        
        operator.ethBalance += msg.value;
    }

    function withdrawOperatorDeposit(bytes20 operatorPublicKeyHash, uint value) public {
        Operator storage operator = operators[operatorPublicKeyHash];
        if (operator.ethAddress != msg.sender) {
            emit ErrorDogeToken(ERR_OPERATOR_NOT_CREATED_OR_WRONG_SENDER);
            return;
        }
        if (operator.ethBalance < value) {
            emit ErrorDogeToken(ERR_OPERATOR_WITHDRAWAL_NOT_ENOUGH_BALANCE);
            return;
        }        
        if ((operator.ethBalance - value) / dogeEthPrice < (operator.dogeAvailableBalance + operator.dogePendingBalance) * collateralRatio) {
            emit ErrorDogeToken(ERR_OPERATOR_WITHDRAWAL_COLLATERAL_WOULD_BE_TOO_LOW);
            return;        
        }
        operator.ethBalance -= value;
        msg.sender.transfer(value);
    }


    function processTransaction(bytes dogeTx, uint txHash, bytes20 operatorPublicKeyHash, address superblockSubmitterAddress) public returns (uint) {
        require(msg.sender == trustedRelayerContract);

        Operator storage operator = operators[operatorPublicKeyHash];
        // Check operator exists 
        if (operator.ethAddress == 0) {
            emit ErrorDogeToken(ERR_PROCESS_OPERATOR_NOT_CREATED);
            return;
        }        

        uint value;
        bytes32 firstInputPublicKeyX;
        bool firstInputPublicKeyOdd;
        uint16 outputIndex;
        (value, firstInputPublicKeyX, firstInputPublicKeyOdd, outputIndex) = DogeTx.parseTransaction(dogeTx, operatorPublicKeyHash);

        // Add tx to the dogeTxHashesAlreadyProcessed
        bool inserted = Set.insert(dogeTxHashesAlreadyProcessed, txHash);
        // Check tx was not already processed
        if (!inserted) {
            emit ErrorDogeToken(ERR_PROCESS_TX_ALREADY_PROCESSED);
            return;        
        }

        // Add utxo
        operator.utxos.push(Utxo(value, txHash, outputIndex));

        // Update operator's doge balance
        operator.dogeAvailableBalance += value;

        // See if the first input was signed by the operator
        bytes20 firstInputPublicKeyHash = DogeTx.pub2PubKeyHash(firstInputPublicKeyX, firstInputPublicKeyOdd);
        if (operatorPublicKeyHash != firstInputPublicKeyHash) {
            // this is a lock tx

            if (value < MIN_LOCK_VALUE) {
                emit ErrorDogeToken(ERR_LOCK_MIN_LOCK_VALUE);
                return;
            }

            processLockTransaction(firstInputPublicKeyX, firstInputPublicKeyOdd, value, 
                                   operator.ethAddress, superblockSubmitterAddress);
            return value;
        } else {
            // this is an unlock tx
            // Update operator's doge balance
            operator.dogePendingBalance -= value;
            return 0;
        }
    }

    function wasDogeTxProcessed(uint txHash) public view returns (bool) {
        return Set.contains(dogeTxHashesAlreadyProcessed, txHash);
    }

    function processLockTransaction(bytes32 firstInputPublicKeyX, bool firstInputPublicKeyOdd,
                                    uint value, address operatorEthAddress, 
                                    address superblockSubmitterAddress) private {
        // Calculate ethereum address from dogecoin public key
        address destinationAddress = DogeTx.pub2address(uint(firstInputPublicKeyX), firstInputPublicKeyOdd);

        uint operatorFee = value * OPERATOR_LOCK_FEE / 1000;
        if (operatorFee < OPERATOR_MIN_LOCK_FEE) {
            operatorFee = OPERATOR_MIN_LOCK_FEE;
        }
        balances[operatorEthAddress] += operatorFee;
        emit NewToken(operatorEthAddress, operatorFee);
        // Hack to make etherscan show the event
        emit Transfer(0, operatorEthAddress, operatorFee);

        uint superblockSubmitterFee = value * SUPERBLOCK_SUBMITTER_LOCK_FEE / 1000;
        if (superblockSubmitterFee < SUPERBLOCK_SUBMITTER_MIN_LOCK_FEE) {
            superblockSubmitterFee = SUPERBLOCK_SUBMITTER_MIN_LOCK_FEE;
        }
        balances[superblockSubmitterAddress] += superblockSubmitterFee;
        emit NewToken(superblockSubmitterAddress, superblockSubmitterFee);
        // Hack to make etherscan show the event
        emit Transfer(0, superblockSubmitterAddress, superblockSubmitterFee);

        uint userValue = value - operatorFee - superblockSubmitterFee;
        balances[destinationAddress] += userValue;
        emit NewToken(destinationAddress, userValue);
        // Hack to make etherscan show the event
        emit Transfer(0, destinationAddress, userValue);    
    }

    // Unlock section begin


    // Request ERC20 tokens to be burnt and dogecoins be received on the doge blockchain
    function doUnlock(string dogeAddress, uint value, bytes20 operatorPublicKeyHash) public returns (bool success) {
        if (value < MIN_UNLOCK_VALUE) {
            emit ErrorDogeToken(ERR_UNLOCK_MIN_UNLOCK_VALUE);
            return;
        }
        if (balances[msg.sender] < value) {
            emit ErrorDogeToken(ERR_UNLOCK_USER_BALANCE);
            return;
        }

        Operator storage operator = operators[operatorPublicKeyHash];
        // Check operator exists 
        if (operator.ethAddress == 0) {
            emit ErrorDogeToken(ERR_UNLOCK_OPERATOR_NOT_CREATED);
            return;
        }
        // Check operator available balance is enough
        if (operator.dogeAvailableBalance < value) {
            emit ErrorDogeToken(ERR_UNLOCK_OPERATOR_BALANCE);
            return;
        }

        uint operatorFee = value * OPERATOR_UNLOCK_FEE / 1000;
        if (operatorFee < OPERATOR_MIN_UNLOCK_FEE) {
            operatorFee = OPERATOR_MIN_UNLOCK_FEE;
        }
        uint unlockValue = value - operatorFee;

        uint32[] memory selectedUtxos;
        uint dogeTxFee;
        uint changeValue;
        uint errorCode;
        (errorCode, selectedUtxos, dogeTxFee, changeValue) = selectUtxosAndFee(unlockValue, operator);
        if (errorCode != 0) {
            emit ErrorDogeToken(errorCode);
            return;
        }

        balances[operator.ethAddress] += operatorFee;
        // Hack to make etherscan show the event
        emit Transfer(msg.sender, operator.ethAddress, operatorFee);
        balances[msg.sender] -= value;
        // Hack to make etherscan show the event
        emit Transfer(msg.sender, 0, unlockValue);

        emit UnlockRequest(unlockIdx, operatorPublicKeyHash);
        unlocksPendingInvestorProof[unlockIdx] = Unlock(msg.sender, dogeAddress, value, 
                                                        operatorFee,
                                                        block.timestamp, selectedUtxos, dogeTxFee,
                                                        operatorPublicKeyHash);
        // Update operator's doge balance
        operator.dogeAvailableBalance -= (unlockValue + changeValue);
        operator.dogePendingBalance += changeValue;
        operator.nextUnspentUtxoIndex += uint32(selectedUtxos.length);
        unlockIdx++;
        return true;
    }

    function selectUtxosAndFee(uint valueToSend, Operator operator) private pure returns (uint errorCode, uint32[] memory selectedUtxos, uint dogeTxFee, uint changeValue) {
        // There should be at least 1 utxo available
        if (operator.nextUnspentUtxoIndex >= operator.utxos.length) {
            errorCode = ERR_UNLOCK_NO_AVAILABLE_UTXOS;
            return (errorCode, selectedUtxos, dogeTxFee, changeValue);
        }
        dogeTxFee = DOGE_TX_BASE_FEE;
        uint selectedUtxosValue;
        uint32 firstSelectedUtxo = operator.nextUnspentUtxoIndex;
        uint32 lastSelectedUtxo = firstSelectedUtxo;
        while (selectedUtxosValue < valueToSend && (lastSelectedUtxo < operator.utxos.length)) {
            selectedUtxosValue += operator.utxos[lastSelectedUtxo].value;
            dogeTxFee += DOGE_TX_FEE_PER_INPUT;
            lastSelectedUtxo++;
        }
        if (selectedUtxosValue < valueToSend) {
            errorCode = ERR_UNLOCK_UTXOS_VALUE_LESS_THAN_VALUE_TO_SEND;
            return (errorCode, selectedUtxos, dogeTxFee, changeValue);
        }
        if (valueToSend <= dogeTxFee) {
            errorCode = ERR_UNLOCK_VALUE_TO_SEND_LESS_THAN_FEE;
            return (errorCode, selectedUtxos, dogeTxFee, changeValue);
        }
        uint32 numberOfSelectedUtxos = lastSelectedUtxo - firstSelectedUtxo;
        selectedUtxos = new uint32[](numberOfSelectedUtxos);
        for(uint32 i = 0; i < numberOfSelectedUtxos; i++) {
            selectedUtxos[i] = i + firstSelectedUtxo;
        }
        changeValue = selectedUtxosValue - valueToSend;
        errorCode = 0;
        return (errorCode, selectedUtxos, dogeTxFee, changeValue);
    }

    function setDogeEthPrice(uint _dogeEthPrice) public {
        require(msg.sender == trustedDogeEthPriceOracle);
        dogeEthPrice = _dogeEthPrice;
    }

    function getUnlockPendingInvestorProof(uint32 index) public view returns (address from, string dogeAddress, uint value, uint operatorFee, uint timestamp, uint32[] selectedUtxos, uint dogeTxFee, bytes20 operatorPublicKeyHash) {
        Unlock storage unlock = unlocksPendingInvestorProof[index];
        from = unlock.from;
        dogeAddress = unlock.dogeAddress;
        value = unlock.value;
        operatorFee = unlock.operatorFee;
        timestamp = unlock.timestamp;
        selectedUtxos = unlock.selectedUtxos;
        dogeTxFee = unlock.dogeTxFee;
        operatorPublicKeyHash = unlock.operatorPublicKeyHash;
    }

    function getUtxosLength(bytes20 operatorPublicKeyHash) public view returns (uint) {
        Operator storage operator = operators[operatorPublicKeyHash];
        return operator.utxos.length;
    }

    function getUtxo(bytes20 operatorPublicKeyHash, uint i) public view returns (uint value, uint txHash, uint16 index) {
        Operator storage operator = operators[operatorPublicKeyHash];
        Utxo storage utxo = operator.utxos[i];
        return (utxo.value, utxo.txHash, utxo.index);
    }

    // Unlock section end
}

    Contract ABI  
[{"constant":true,"inputs":[],"name":"MIN_UNLOCK_VALUE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"SUPERBLOCK_SUBMITTER_MIN_LOCK_FEE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes20"}],"name":"operators","outputs":[{"name":"ethAddress","type":"address"},{"name":"dogeAvailableBalance","type":"uint256"},{"name":"dogePendingBalance","type":"uint256"},{"name":"nextUnspentUtxoIndex","type":"uint32"},{"name":"ethBalance","type":"uint256"},{"name":"operatorKeyIndex","type":"uint24"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint32"}],"name":"unlocksPendingInvestorProof","outputs":[{"name":"from","type":"address"},{"name":"dogeAddress","type":"string"},{"name":"value","type":"uint256"},{"name":"operatorFee","type":"uint256"},{"name":"timestamp","type":"uint256"},{"name":"dogeTxFee","type":"uint256"},{"name":"operatorPublicKeyHash","type":"bytes20"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"operatorPublicKeyHash","type":"bytes20"}],"name":"getUtxosLength","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dogeAddress","type":"string"},{"name":"value","type":"uint256"},{"name":"operatorPublicKeyHash","type":"bytes20"}],"name":"doUnlock","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"operatorPublicKeyHash","type":"bytes20"}],"name":"addOperatorDeposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"unlockIdx","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"operatorPublicKeyCompressed","type":"bytes"},{"name":"signature","type":"bytes"}],"name":"addOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"operatorPublicKeyHash","type":"bytes20"}],"name":"deleteOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"operatorPublicKeyHash","type":"bytes20"},{"name":"value","type":"uint256"}],"name":"withdrawOperatorDeposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"OPERATOR_UNLOCK_FEE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"txHash","type":"uint256"}],"name":"wasDogeTxProcessed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"collateralRatio","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MIN_LOCK_VALUE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SUPERBLOCK_SUBMITTER_LOCK_FEE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOperatorsLength","outputs":[{"name":"","type":"uint24"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_dogeEthPrice","type":"uint256"}],"name":"setDogeEthPrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"dogeTx","type":"bytes"},{"name":"txHash","type":"uint256"},{"name":"operatorPublicKeyHash","type":"bytes20"},{"name":"superblockSubmitterAddress","type":"address"}],"name":"processTransaction","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"operatorKeys","outputs":[{"name":"key","type":"bytes20"},{"name":"deleted","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"trustedRelayerContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"OPERATOR_LOCK_FEE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"index","type":"uint32"}],"name":"getUnlockPendingInvestorProof","outputs":[{"name":"from","type":"address"},{"name":"dogeAddress","type":"string"},{"name":"value","type":"uint256"},{"name":"operatorFee","type":"uint256"},{"name":"timestamp","type":"uint256"},{"name":"selectedUtxos","type":"uint32[]"},{"name":"dogeTxFee","type":"uint256"},{"name":"operatorPublicKeyHash","type":"bytes20"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"operatorPublicKeyHash","type":"bytes20"},{"name":"i","type":"uint256"}],"name":"getUtxo","outputs":[{"name":"value","type":"uint256"},{"name":"txHash","type":"uint256"},{"name":"index","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"trustedDogeEthPriceOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"OPERATOR_MIN_UNLOCK_FEE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dogeEthPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"OPERATOR_MIN_LOCK_FEE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_trustedRelayerContract","type":"address"},{"name":"_trustedDogeEthPriceOracle","type":"address"},{"name":"_collateralRatio","type":"uint8"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"err","type":"uint256"}],"name":"ErrorDogeToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"NewToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint32"},{"indexed":false,"name":"operatorPublicKeyHash","type":"bytes20"}],"name":"UnlockRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]

  Contract Creation Code Switch To Opcodes View
60c0604052600460808190527f48302e310000000000000000000000000000000000000000000000000000000060a09081526200004091600691906200018e565b503480156200004e57600080fd5b50604051606080620038dc833981016040818152825160208085015194830151838501845260098086527f446f6765546f6b656e0000000000000000000000000000000000000000000000838701908152855180870187529182527f444f4745544f4b454e00000000000000000000000000000000000000000000008285015233600090815260019094529483208390558280558551939695919492939192600892620000fe916003916200018e565b506004805460ff191660ff84161790558051620001239060059060208401906200018e565b505060078054600160a060020a03978816600160a060020a0319918216179091556008805460ff909616740100000000000000000000000000000000000000000260a060020a60ff021997909816959091169490941794909416949094179091555062000233915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620001d157805160ff191683800117855562000201565b8280016001018555821562000201579182015b8281111562000201578251825591602001919060010190620001e4565b506200020f92915062000213565b5090565b6200023091905b808211156200020f57600081556001016200021a565b90565b61369980620002436000396000f3006080604052600436106101c95763ffffffff60e060020a60003504166305347cdc81146101ce57806306fdde03146101f5578063095ea7b31461027f57806316931c94146102b757806318160ddd146102cc57806323b872dd146102e1578063313ce5671461030b5780633e9745311461033657806341f7a1f71461039f5780634b48a8421461047557806354fd4d501461049757806355569d7f146104ac5780635be3b1b914610517578063636a85151461052e578063657857de1461055c5780636d440c6b146105f357806370a08231146106155780637b837b7a1461063657806395c39bf61461065b57806395d89b41146106705780639ed0031614610685578063a9059cbb1461069d578063b4eae1cb146106c1578063b52d521d146101ce578063b85278a91461065b578063ba24ecab146106d6578063c0f76faf14610703578063c3d5e1861461071b578063c5a4a2b714610793578063cae9ca51146107cf578063cf496b1014610838578063d48839911461065b578063d48e6a9a14610869578063d63ceb461461099a578063dd62ed3e146109e1578063dd8f13bb14610a08578063ef90f371146102b7578063f5b2040014610a1d578063fcd5d384146102b7575b600080fd5b3480156101da57600080fd5b506101e3610a32565b60408051918252519081900360200190f35b34801561020157600080fd5b5061020a610a3a565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561024457818101518382015260200161022c565b50505050905090810190601f1680156102715780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561028b57600080fd5b506102a3600160a060020a0360043516602435610ac8565b604080519115158252519081900360200190f35b3480156102c357600080fd5b506101e3610b2e565b3480156102d857600080fd5b506101e3610b36565b3480156102ed57600080fd5b506102a3600160a060020a0360043581169060243516604435610b3c565b34801561031757600080fd5b50610320610c09565b6040805160ff9092168252519081900360200190f35b34801561034257600080fd5b506103586001606060020a031960043516610c12565b60408051600160a060020a03909716875260208701959095528585019390935263ffffffff9091166060850152608084015262ffffff1660a0830152519081900360c00190f35b3480156103ab57600080fd5b506103bd63ffffffff60043516610c5d565b60408051600160a060020a0389168152908101869052606081018590526080810184905260a081018390526001606060020a0319821660c082015260e0602080830182815289519284019290925288516101008401918a019080838360005b8381101561043457818101518382015260200161041c565b50505050905090810190601f1680156104615780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b34801561048157600080fd5b506101e36001606060020a031960043516610d3f565b3480156104a357600080fd5b5061020a610d5e565b3480156104b857600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526102a394369492936024939284019190819084018382808284375094975050843595505050506020909101356001606060020a0319169050610db9565b61052c6001606060020a0319600435166112b1565b005b34801561053a57600080fd5b50610543611312565b6040805163ffffffff9092168252519081900360200190f35b34801561056857600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261052c94369492936024939284019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a9998810197919650918201945092508291508401838280828437509497506113379650505050505050565b3480156105ff57600080fd5b5061052c6001606060020a03196004351661168b565b34801561062157600080fd5b506101e3600160a060020a0360043516611803565b34801561064257600080fd5b5061052c6001606060020a03196004351660243561181e565b34801561066757600080fd5b506101e3611943565b34801561067c57600080fd5b5061020a611948565b34801561069157600080fd5b506102a36004356119a3565b3480156106a957600080fd5b506102a3600160a060020a0360043516602435611a32565b3480156106cd57600080fd5b50610320611aaa565b3480156106e257600080fd5b506106eb611acb565b6040805162ffffff9092168252519081900360200190f35b34801561070f57600080fd5b5061052c600435611ad2565b34801561072757600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526101e3943694929360249392840191908190840183828082843750949750508435955050505060208201356001606060020a0319169160400135600160a060020a03169050611aee565b34801561079f57600080fd5b506107ab600435611d3c565b604080516001606060020a0319909316835290151560208301528051918290030190f35b3480156107db57600080fd5b50604080516020600460443581810135601f81018490048402850184019095528484526102a3948235600160a060020a0316946024803595369594606494920191908190840183828082843750949750611d869650505050505050565b34801561084457600080fd5b5061084d611f21565b60408051600160a060020a039092168252519081900360200190f35b34801561087557600080fd5b5061088763ffffffff60043516611f30565b6040518089600160a060020a0316600160a060020a031681526020018060200188815260200187815260200186815260200180602001858152602001846bffffffffffffffffffffffff19166bffffffffffffffffffffffff1916815260200183810383528a818151815260200191508051906020019080838360005b8381101561091c578181015183820152602001610904565b50505050905090810190601f1680156109495780820380516001836020036101000a031916815260200191505b508381038252865181528651602091820191808901910280838360005b8381101561097e578181015183820152602001610966565b505050509050019a505050505050505050505060405180910390f35b3480156109a657600080fd5b506109bf6001606060020a0319600435166024356120be565b60408051938452602084019290925261ffff1682820152519081900360600190f35b3480156109ed57600080fd5b506101e3600160a060020a0360043581169060243516612120565b348015610a1457600080fd5b5061084d61214b565b348015610a2957600080fd5b506101e361215a565b6311e1a30081565b6003805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ac05780601f10610a9557610100808354040283529160200191610ac0565b820191906000526020600020905b815481529060010190602001808311610aa357829003601f168201915b505050505081565b336000818152600260209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b6305f5e10081565b60005481565b600160a060020a0383166000908152600160205260408120548211801590610b875750600160a060020a03841660009081526002602090815260408083203384529091529020548211155b1515610b9257600080fd5b600160a060020a038084166000818152600160209081526040808320805488019055938816808352848320805488900390556002825284832033845282529184902080548790039055835186815293519293919260008051602061364e8339815191529281900390910190a35060015b9392505050565b60045460ff1681565b600b60205260009081526040902080546001820154600283015460048401546005850154600690950154600160a060020a03909416949293919263ffffffff9091169162ffffff1686565b6009602090815260009182526040918290208054600180830180548651600261010094831615949094026000190190911692909204601f8101869004860283018601909652858252600160a060020a03909216949293909290830182828015610d075780601f10610cdc57610100808354040283529160200191610d07565b820191906000526020600020905b815481529060010190602001808311610cea57829003601f168201915b50505060028401546003850154600486015460068701546007909701549596929591945092506c010000000000000000000000000287565b6001606060020a0319166000908152600b602052604090206003015490565b6006805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ac05780601f10610a9557610100808354040283529160200191610ac0565b600080600080606060008060006311e1a3008a1015610dfa576040805161eab08152905160008051602061362e8339815191529181900360200190a16112a3565b336000908152600160205260409020548a1115610e39576040805161eaba8152905160008051602061362e8339815191529181900360200190a16112a3565b6001606060020a031989166000908152600b602052604090208054909750600160a060020a03161515610e8e576040805161eac48152905160008051602061362e8339815191529181900360200190a16112a3565b8987600101541015610ec2576040805161eace8152905160008051602061362e8339815191529181900360200190a16112a3565b6103e8600a8b020495506305f5e100861015610ee0576305f5e10095505b6040805160e0810182528854600160a060020a03168152600189015460208083019190915260028a01548284015260038a0180548451818402810184019095528085528a8f039950610fc5948a94938d936060860193909160009084015b82821015610f8e5760008481526020908190206040805160608101825260038602909201805483526001808201548486015260029091015461ffff16918301919091529083529092019101610f3e565b50505090825250600482015463ffffffff1660208201526005820154604082015260069091015462ffffff16606090910152612160565b9196509450925090508015610ffa5760408051828152905160008051602061362e8339815191529181900360200190a16112a3565b8654600160a060020a0390811660009081526001602090815260409182902080548a019055895482518a81529251931692339260008051602061364e83398151915292908290030190a333600081815260016020908152604080832080548f900390558051898152905192939260008051602061364e833981519152929181900390910190a360085460408051750100000000000000000000000000000000000000000090920463ffffffff1682526001606060020a03198b16602083015280517fa452c19abf34fda31e59719208cf19c16be3dc9573465e8bf2ec1e4e89d3fad89281900390910190a1604080516101008101825233815260208082018e81528284018e9052606083018a905242608084015260a0830188905260c083018790526001606060020a03198d1660e08401526008547501000000000000000000000000000000000000000000900463ffffffff16600090815260098352939093208251815473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039091161781559251805192939261119b9260018501920190613443565b5060408201516002820155606082015160038201556080820151600482015560a082015180516111d59160058401916020909101906134c1565b5060c0820151600682015560e0909101516007909101805473ffffffffffffffffffffffffffffffffffffffff19166c01000000000000000000000000909204919091179055600187810180548488019003905560028801805484019055845160048901805463ffffffff19811663ffffffff91821690930181169290921790556008805478ffffffff000000000000000000000000000000000000000000198116750100000000000000000000000000000000000000000091829004841685019093160291909117905597505b505050505050509392505050565b6001606060020a031981166000908152600b602052604090208054600160a060020a03163314611303576040805161ea748152905160008051602061362e8339815191529181900360200190a161130e565b600581018054340190555b5050565b6008547501000000000000000000000000000000000000000000900463ffffffff1681565b60008060008060008087600081518110151561134f57fe5b90602001015160f860020a900460f860020a02600160f860020a031916600360f860020a0214945060218801519550600280336040516020018082600160a060020a0316600160a060020a03166c010000000000000000000000000281526014019150506040516020818303038152906040526040518082805190602001908083835b602083106113f15780518252601f1990920191602091820191016113d2565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015611432573d6000803e3d6000fd5b5050506040513d602081101561144757600080fd5b50516040805160208181019390935281518082038401815290820191829052805190928291908401908083835b602083106114935780518252601f199092019160209182019101611474565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af11580156114d4573d6000803e3d6000fd5b5050506040513d60208110156114e957600080fd5b505193506114f784886122bc565b92506115038686612393565b600160a060020a0384811691161461153d576040805161ea6a8152905160008051602061362e8339815191529181900360200190a1611681565b61154786866124a7565b6001606060020a031981166000908152600b6020526040902080549193509150600160a060020a03161561159d576040805161ea6f8152905160008051602061362e8339815191529181900360200190a1611681565b80543373ffffffffffffffffffffffffffffffffffffffff19918216178255600c805460068401805462ffffff191662ffffff909216919091179055604080518082019091526001606060020a03198516815260006020820181815283546001810185559390915290517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790920180549151919093166c010000000000000000000000009092049190911774ff0000000000000000000000000000000000000000191674010000000000000000000000000000000000000000911515919091021790555b5050505050505050565b6001606060020a031981166000908152600b602052604081208054909190600160a060020a031633146116e0576040805161ea748152905160008051602061362e8339815191529181900360200190a16117fe565b60018201541515806116f55750600282015415155b806117035750600582015415155b15611730576040805161ea7e8152905160008051602061362e8339815191529181900360200190a16117fe565b6006820154600c8054909162ffffff1690811061174957fe5b60009182526020808320909101805474ff00000000000000000000000000000000000000001916740100000000000000000000000000000000000000001781556001606060020a031986168352600b90915260408220805473ffffffffffffffffffffffffffffffffffffffff191681556001810183905560028101839055909250906117d9600383018261356c565b5060048101805463ffffffff1916905560006005820155600601805462ffffff191690555b505050565b600160a060020a031660009081526001602052604090205490565b6001606060020a031982166000908152600b602052604090208054600160a060020a03163314611870576040805161ea748152905160008051602061362e8339815191529181900360200190a16117fe565b81816005015410156118a4576040805161ea888152905160008051602061362e8339815191529181900360200190a16117fe565b600860149054906101000a900460ff1660ff16816002015482600101540102600a54838360050154038115156118d657fe5b041015611905576040805161ea928152905160008051602061362e8339815191529181900360200190a16117fe565b6005810180548390039055604051339083156108fc029084906000818181858888f1935050505015801561193d573d6000803e3d6000fd5b50505050565b600a81565b6005805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ac05780601f10610a9557610100808354040283529160200191610ac0565b60007362d6203411988089cb6059c6370b407ab2010eb6636ce8e081600d846040518363ffffffff1660e060020a028152600401808381526020018281526020019250505060206040518083038186803b158015611a0057600080fd5b505af4158015611a14573d6000803e3d6000fd5b505050506040513d6020811015611a2a57600080fd5b505192915050565b33600090815260016020526040812054821115611a4e57600080fd5b33600081815260016020908152604080832080548790039055600160a060020a038716808452928190208054870190558051868152905192939260008051602061364e833981519152929181900390910190a350600192915050565b60085474010000000000000000000000000000000000000000900460ff1681565b600c545b90565b600854600160a060020a03163314611ae957600080fd5b600a55565b6007546000908190819081908190819081908190600160a060020a03163314611b1657600080fd5b6001606060020a03198a166000908152600b602052604090208054909750600160a060020a03161515611b6b576040805161ea9c8152905160008051602061362e8339815191529181900360200190a1611d2d565b611b758c8b612678565b809650819750829850839950505050507362d6203411988089cb6059c6370b407ab2010eb663831cb739600d8d6040518363ffffffff1660e060020a028152600401808381526020018281526020019250505060206040518083038186803b158015611be057600080fd5b505af4158015611bf4573d6000803e3d6000fd5b505050506040513d6020811015611c0a57600080fd5b50519150811515611c3d576040805161eaa68152905160008051602061362e8339815191529181900360200190a1611d2d565b6040805160608101825287815260208082018e815261ffff87811694840194855260038c81018054600180820183556000928352959091209551910290940193845590518383015592516002909201805461ffff191692909316919091179091558701805487019055611cb085856124a7565b90506001606060020a03198a811690821614611d1d576311e1a300861015611cfa576040805161eaf68152905160008051602061362e8339815191529181900360200190a1611d2d565b8654611d1590869086908990600160a060020a03168d612827565b859750611d2d565b6002870180548790039055600097505b50505050505050949350505050565b600c805482908110611d4a57fe5b6000918252602090912001546c010000000000000000000000008102915074010000000000000000000000000000000000000000900460ff1682565b336000818152600260209081526040808320600160a060020a038816808552908352818420879055815187815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a383600160a060020a031660405180807f72656365697665417070726f76616c28616464726573732c75696e743235362c81526020017f616464726573732c627974657329000000000000000000000000000000000000815250602e019050604051809103902060e060020a9004338530866040518563ffffffff1660e060020a0281526004018085600160a060020a0316600160a060020a0316815260200184815260200183600160a060020a0316600160a060020a03168152602001828051906020019080838360005b83811015611ec6578181015183820152602001611eae565b50505050905090810190601f168015611ef35780820380516001836020036101000a031916815260200191505b509450505050506000604051808303816000875af1925050501515611f1757600080fd5b5060019392505050565b600754600160a060020a031681565b63ffffffff811660009081526009602090815260408083208054600180830180548551600261010094831615949094026000190190911692909204601f8101879004870283018701909552848252600160a060020a039092169560609590948594859488948694859491929190830182828015611fee5780601f10611fc357610100808354040283529160200191611fee565b820191906000526020600020905b815481529060010190602001808311611fd157829003601f168201915b505050505097508060020154965080600301549550806004015494508060050180548060200260200160405190810160405280929190818152602001828054801561208457602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116120475790505b50505050509350806006015492508060070160009054906101000a90046c0100000000000000000000000002915050919395975091939597565b6001606060020a031982166000908152600b60205260408120600381018054839283929091839190879081106120f057fe5b6000918252602090912060039091020180546001820154600290920154909991985061ffff169650945050505050565b600160a060020a03918216600090815260026020908152604080832093909416825291909152205490565b600854600160a060020a031681565b600a5481565b6000606060008060008060008060008960600151518a6080015163ffffffff161015156121915761ead898506122ae565b6302faf0809650896080015193508392505b8a851080156121bc57508960600151518363ffffffff16105b156121fd5760608a0151805163ffffffff85169081106121d857fe5b60209081029091010151516305f5e100979097019694909401936001909201916121a3565b8a85101561220f5761eae298506122ae565b868b116122205761eaec98506122ae565b83830391508163ffffffff16604051908082528060200260200182016040528015612255578160200160208202803883390190505b509750600090505b8163ffffffff168163ffffffff1610156122a457838101888263ffffffff1681518110151561228857fe5b63ffffffff90921660209283029091019091015260010161225d565b600098508a850395505b505050505092959194509250565b600080600080845160411415156122d6576000935061238a565b505050602082015160218301516041840151909160001a601b60ff821610156122fd57601b015b8060ff16601b1415801561231557508060ff16601c14155b15612323576000935061238a565b60408051600080825260208083018085528a905260ff8516838501526060830187905260808301869052925160019360a0808501949193601f19840193928390039091019190865af115801561237d573d6000803e3d6000fd5b5050506020604051035193505b50505092915050565b600080806401000003d01985860991506401000003d01985830991506401000003d0196007830891506123ed827f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c6401000003d019612a10565b905060018082161484151514612406576401000003d019035b6401000003d019818209821461241b57600080fd5b848160405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b602083106124725780518252601f199092019160209182019101612453565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912098975050505050505050565b600080826124d5577f02000000000000000000000000000000000000000000000000000000000000006124f7565b7f03000000000000000000000000000000000000000000000000000000000000005b604080517fff0000000000000000000000000000000000000000000000000000000000000083166020808301919091526021808301899052835180840390910181526041909201928390528151939450600393600293918291908401908083835b602083106125775780518252601f199092019160209182019101612558565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af11580156125b8573d6000803e3d6000fd5b5050506040513d60208110156125cd57600080fd5b50516040805160208181019390935281518082038401815290820191829052805190928291908401908083835b602083106126195780518252601f1990920191602091820191016125fa565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af115801561265a573d6000803e3d6000fd5b5050604051516c010000000000000000000000000295945050505050565b600080600080612686613590565b600480825260609081908190819081906126a3908d906000612a5a565b885281519096509094506126cf908d90869060009081106126c057fe5b90602001906020020151612b63565b151560a0880152608087015285516126ea908d906002612b92565b89528151909550909350909150612732908d908490600090811061270a57fe5b9060200190602002015185600081518110151561272357fe5b90602001906020020151612cf0565b6001606060020a031916602087015280518190600090811061275057fe5b60209081029091018101516040880152600060608801528601516001606060020a0319908116908c16146127df576127aa8c83600181518110151561279157fe5b9060200190602002015185600181518110151561272357fe5b6001606060020a03191660208701528051819060019081106127c857fe5b602090810290910101516040870152600160608701525b60208601516001606060020a03198c81169116146127fc57600080fd5b856040015186608001518760a001518860600151995099509950995050505050505092959194509250565b60008080806128368989612393565b93506103e8600a88020492506305f5e100831015612856576305f5e10092505b600160a060020a038616600081815260016020908152604091829020805487019055815186815291517f275a11e033325e9b28a23131fcc7e243a49bb38beb686051976dd8c8899d9a3c9281900390910190a2604080518481529051600160a060020a0388169160009160008051602061364e8339815191529181900360200190a36103e8600a88020491506305f5e1008210156128f6576305f5e10091505b600160a060020a038516600081815260016020908152604091829020805486019055815185815291517f275a11e033325e9b28a23131fcc7e243a49bb38beb686051976dd8c8899d9a3c9281900390910190a2604080518381529051600160a060020a0387169160009160008051602061364e8339815191529181900360200190a350600160a060020a0383166000818152600160209081526040918290208054868b03869003908101909155825181815292519093927f275a11e033325e9b28a23131fcc7e243a49bb38beb686051976dd8c8899d9a3c92908290030190a2604080518281529051600160a060020a0386169160009160008051602061364e8339815191529181900360200190a3505050505050505050565b600060405160208152602080820152602060408201528460608201528360808201528260a082015260208160c08360006005600019f11515612a5157600080fd5b51949350505050565b6060806000806000806060806000612a728c8c612d1b565b9b509550891580612a825750858a115b15612a8f57859450612a93565b8994505b84604051908082528060200260200182016040528015612abd578160200160208202803883390190505b50925084604051908082528060200260200182016040528015612aea578160200160208202803883390190505b509150600090505b84811015612b53578a8382815181101515612b0957fe5b6020908102909101015260249a909a0199612b248c8c612d1b565b8351909c509094508490839083908110612b3a57fe5b6020908102909101015299830160040199600101612af2565b50909a9099509650505050505050565b6024016000808080612b758686612d1b565b9550612b8390508686612ddd565b50909890975095505050505050565b606080606060008060008060608060606000612bae8e8e612d1b565b9d5096508b1580612bbe5750868c115b15612bcb57869550612bcf565b8b95505b85604051908082528060200260200182016040528015612bf9578160200160208202803883390190505b50935085604051908082528060200260200182016040528015612c26578160200160208202803883390190505b50925085604051908082528060200260200182016040528015612c53578160200160208202803883390190505b509150600090505b85811015612cde57612c6f8e8e6040612e14565b8282815181101515612c7d57fe5b6020908102909101015260089c909c019b612c988e8e612d1b565b8551909e509095508d90859083908110612cae57fe5b6020908102909101015282518590849083908110612cc857fe5b602090810290910101529b84019b600101612c5b565b509c919b509998509650505050505050565b6000612cfd848484613135565b15612d1657612d0f848460030161327b565b9050610c02565b610c02565b60008060008484815181101515612d2e57fe5b90602001015160f860020a900460f860020a0260f860020a9004905060018401935060fd8160ff161015612d6a5760ff81169250839150612dd5565b8060ff1660fd1415612d8f57612d8285856010612e14565b8460020192509250612dd5565b8060ff1660fe1415612db457612da785856020612e14565b8460040192509250612dd5565b8060ff1660ff1415612dd557612dcc85856040612e14565b84600801925092505b509250929050565b606060008060006060600080612df389896132f0565b98509250612e018989613371565b949b919a50985092965091945050505050565b60008160081415612e51578383815181101515612e2d57fe5b90602001015160f860020a900460f860020a0260f860020a900460ff169050610c02565b8160101415612ebd578383600101815181101515612e6b57fe5b90602001015160f860020a900460f860020a0260f860020a9004610100028484815181101515612e9757fe5b90602001015160f860020a900460f860020a0260f860020a90040161ffff169050610c02565b8160201415612f8e578383600301815181101515612ed757fe5b90602001015160f860020a900460f860020a0260f860020a90046301000000028484600201815181101515612f0857fe5b90602001015160f860020a900460f860020a0260f860020a900462010000028585600101815181101515612f3857fe5b90602001015160f860020a900460f860020a0260f860020a9004610100028686815181101515612f6457fe5b90602001015160f860020a900460f860020a0260f860020a900401010163ffffffff169050610c02565b8160401415610c02578383600701815181101515612fa857fe5b90602001015160f860020a900460f860020a0260f860020a9004670100000000000000028484600601815181101515612fdd57fe5b90602001015160f860020a900460f860020a0260f860020a9004660100000000000002858560050181518110151561301157fe5b90602001015160f860020a900460f860020a0260f860020a90046501000000000002868660040181518110151561304457fe5b90602001015160f860020a900460f860020a0260f860020a900464010000000002878760030181518110151561307657fe5b90602001015160f860020a900460f860020a0260f860020a900463010000000288886002018151811015156130a757fe5b90602001015160f860020a900460f860020a0260f860020a9004620100000289896001018151811015156130d757fe5b90602001015160f860020a900460f860020a0260f860020a9004610100028a8a81518110151561310357fe5b90602001015160f860020a900460f860020a0260f860020a90040101010101010167ffffffffffffffff169050610c02565b60008160191480156131775750838381518110151561315057fe5b90602001015160f860020a900460f860020a02600160f860020a031916607660f860020a02145b80156131b65750838360010181518110151561318f57fe5b90602001015160f860020a900460f860020a02600160f860020a03191660a960f860020a02145b80156131f5575083836002018151811015156131ce57fe5b90602001015160f860020a900460f860020a02600160f860020a031916601460f860020a02145b80156132345750838360170181518110151561320d57fe5b90602001015160f860020a900460f860020a02600160f860020a031916608860f860020a02145b80156132735750838360180181518110151561324c57fe5b90602001015160f860020a900460f860020a02600160f860020a03191660ac60f860020a02145b949350505050565b600080805b60148110156132d95780601303600802858583018151811015156132a057fe5b90602001015160f860020a900460f860020a0260f860020a9004600160a060020a03169060020a02820191508080600101915050613280565b506c01000000000000000000000000029392505050565b606060008060606133018686613413565b95509150600960ff83161080159061331d575060498260ff1611155b151561332857600080fd5b858581518110151561333657fe5b90602001015160f860020a900460f860020a0260f860020a900460ff16603014151561336157600080fd5b9560ff9091169390930193505050565b6000806000806000806133848888613413565b97509250602160ff84161461339857600080fd5b87878151811015156133a657fe5b6020910101519787016021908101519960f860020a998a90049099027fff00000000000000000000000000000000000000000000000000000000000000167f0300000000000000000000000000000000000000000000000000000000000000149897019695505050505050565b600080838381518110151561342457fe5b016020015160f860020a90819004810204915050600182019250929050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061348457805160ff19168380011785556134b1565b828001600101855582156134b1579182015b828111156134b1578251825591602001919060010190613496565b506134bd9291506135c5565b5090565b828054828255906000526020600020906007016008900481019282156135605791602002820160005b8382111561352e57835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026134ea565b801561355e5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261352e565b505b506134bd9291506135df565b508054600082556003029060005260206000209081019061358d9190613600565b50565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b611acf91905b808211156134bd57600081556001016135cb565b611acf91905b808211156134bd57805463ffffffff191681556001016135e5565b611acf91905b808211156134bd576000808255600182015560028101805461ffff191690556003016136065600b56073699a886ff0a9e8b995881e51b5ccd562594c835e990ad2f7c35957a5a4ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820b2d9991d82c68ab94a16a6bb223e44793b4a3520e67c5cf3943ae44f5c571d700029000000000000000000000000c48ea9d53c243867b71fadf7e57a4caf6642f8de000000000000000000000000f001a51533bcd531d7a2f40a4579afcc19038c140000000000000000000000000000000000000000000000000000000000000002

    Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c48ea9d53c243867b71fadf7e57a4caf6642f8de000000000000000000000000f001a51533bcd531d7a2f40a4579afcc19038c140000000000000000000000000000000000000000000000000000000000000002

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000c48ea9d53c243867b71fadf7e57a4caf6642f8de
Arg [1] : 000000000000000000000000f001a51533bcd531d7a2f40a4579afcc19038c14
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000002


   Library Used
Set : 0x62D6203411988089cb6059C6370b407Ab2010eB6

   Swarm Source:
bzzr://b2d9991d82c68ab94a16a6bb223e44793b4a3520e67c5cf3943ae44f5c571d70

 

View All
Block Age transaction Difficulty GasUsed Reward
View All
Block Age UncleNumber Difficulty GasUsed Reward