ETH Price: $2,126.27 (+1.87%)

Transaction Decoder

Block:
5065990 at Feb-10-2018 04:47:47 PM +UTC
Transaction Fee:
0.0003181 ETH $0.68
Gas Used:
63,620 Gas / 5 Gwei

Emitted Events:

39 FiCoin.Transfer( from=[Receiver] TokenStore, to=[Sender] 0x30d6414b376ae751b3b914a6a1bcfb72c5cf52e5, value=1415000000000000000000 )
40 TokenStore.Withdraw( token=FiCoin, user=[Sender] 0x30d6414b376ae751b3b914a6a1bcfb72c5cf52e5, amount=1415000000000000000000, balance=1374498193189 )

Account State Difference:

  Address   Before After State Difference Code
0x1cE7AE55...ee6Ee33D8
(Token.Store)
0x30d6414b...2c5Cf52E5
0.0099829983 Eth
Nonce: 10
0.0096648983 Eth
Nonce: 11
0.0003181
0x4c251de8...ddD0b0fE7
(F2Pool Old)
3,273.415297674100207149 Eth3,273.415615774100207149 Eth0.0003181

Execution Trace

TokenStore.withdrawToken( _token=0x4c251de85Ad3498c5b89388d8efc696ddD0b0fE7, _amount=1415000000000000000000 )
  • FiCoin.transfer( _to=0x30d6414b376ae751B3b914A6A1BCFB72c5Cf52E5, _value=1415000000000000000000 ) => ( True )
    File 1 of 2: TokenStore
    pragma solidity ^0.4.11;
    
    // ERC20 token protocol, see more details at
    // https://theethereum.wiki/w/index.php/ERC20_Token_Standard
    // And also https://github.com/ethereum/eips/issues/20
    
    contract Token {
      function totalSupply() constant returns (uint256 supply);
      function balanceOf(address _owner) constant returns (uint256 balance);
      function transfer(address _to, uint256 _value) returns (bool success);
      function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
      function approve(address _spender, uint256 _value) returns (bool success);
      function allowance(address _owner, address _spender) constant returns (uint256 remaining);
    
      event Transfer(address indexed _from, address indexed _to, uint256 _value);
      event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    }
    
    // Safe mathematics to make the code more readable
    
    contract SafeMath {
      function safeMul(uint a, uint b) internal returns (uint) {
        uint c = a * b;
        assert(a == 0 || c / a == b);
        return c;
      }
    
      function safeSub(uint a, uint b) internal returns (uint) {
        assert(b <= a);
        return a - b;
      }
    
      function safeAdd(uint a, uint b) internal returns (uint) {
        uint c = a + b;
        assert(c>=a && c>=b);
        return c;
      }
    }
    
    // Ownable interface to simplify owner checks
    
    contract Ownable {
      address public owner;
    
      function Ownable() {
        owner = msg.sender;
      }
    
      modifier onlyOwner() {
        require(msg.sender == owner);
        _;
      }
    
      function transferOwnership(address _newOwner) onlyOwner {
        require(_newOwner != address(0));
        owner = _newOwner;
      }
    }
    
    // Interface for trading discounts and rebates for specific accounts
    
    contract AccountModifiersInterface {
      function accountModifiers(address _user) constant returns(uint takeFeeDiscount, uint rebatePercentage);
      function tradeModifiers(address _maker, address _taker) constant returns(uint takeFeeDiscount, uint rebatePercentage);
    }
    
    // Interface for trade tacker
    
    contract TradeTrackerInterface {
      function tradeComplete(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, address _get, address _give, uint _takerFee, uint _makerRebate);
    }
    
    // Exchange contract
    
    contract TokenStore is SafeMath, Ownable {
    
      // The account that will receive fees
      address feeAccount;
    
      // The account that stores fee discounts/rebates
      address accountModifiers;
      
      // Trade tracker account
      address tradeTracker;
    
      // We charge only the takers and this is the fee, percentage times 1 ether
      uint public fee;
    
      // Mapping of token addresses to mapping of account balances (token 0 means Ether)
      mapping (address => mapping (address => uint)) public tokens;
    
      // Mapping of user accounts to mapping of order hashes to uints (amount of order that has been filled)
      mapping (address => mapping (bytes32 => uint)) public orderFills;
      
      // Address of a next and previous versions of the contract, also status of the contract
      // can be used for user-triggered fund migrations
      address public successor;
      address public predecessor;
      bool public deprecated;
      uint16 public version;
    
      // Logging events
      // Note: Order creation is handled off-chain, see explanation further below
      event Cancel(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s);
      event Trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address get, address give, uint nonce);
      event Deposit(address token, address user, uint amount, uint balance);
      event Withdraw(address token, address user, uint amount, uint balance);
      event FundsMigrated(address user);
    
      function TokenStore(uint _fee, address _predecessor) {
        feeAccount = owner;
        fee = _fee;
        predecessor = _predecessor;
        deprecated = false;
        if (predecessor != address(0)) {
          version = TokenStore(predecessor).version() + 1;
        } else {
          version = 1;
        }
      }
    
      // Throw on default handler to prevent direct transactions of Ether
      function() {
        revert();
      }
      
      modifier deprecable() {
        require(!deprecated);
        _;
      }
    
      function deprecate(bool _deprecated, address _successor) onlyOwner {
        deprecated = _deprecated;
        successor = _successor;
      }
    
      function changeFeeAccount(address _feeAccount) onlyOwner {
        require(_feeAccount != address(0));
        feeAccount = _feeAccount;
      }
    
      function changeAccountModifiers(address _accountModifiers) onlyOwner {
        accountModifiers = _accountModifiers;
      }
      
      function changeTradeTracker(address _tradeTracker) onlyOwner {
        tradeTracker = _tradeTracker;
      }
    
      // Fee can only be decreased!
      function changeFee(uint _fee) onlyOwner {
        require(_fee <= fee);
        fee = _fee;
      }
      
      // Allows a user to get her current discount/rebate
      function getAccountModifiers() constant returns(uint takeFeeDiscount, uint rebatePercentage) {
        if (accountModifiers != address(0)) {
          return AccountModifiersInterface(accountModifiers).accountModifiers(msg.sender);
        } else {
          return (0, 0);
        }
      }
      
      ////////////////////////////////////////////////////////////////////////////////
      // Deposits, withdrawals, balances
      ////////////////////////////////////////////////////////////////////////////////
    
      function deposit() payable deprecable {
        tokens[0][msg.sender] = safeAdd(tokens[0][msg.sender], msg.value);
        Deposit(0, msg.sender, msg.value, tokens[0][msg.sender]);
      }
    
      function withdraw(uint _amount) {
        require(tokens[0][msg.sender] >= _amount);
        tokens[0][msg.sender] = safeSub(tokens[0][msg.sender], _amount);
        if (!msg.sender.call.value(_amount)()) {
          revert();
        }
        Withdraw(0, msg.sender, _amount, tokens[0][msg.sender]);
      }
    
      function depositToken(address _token, uint _amount) deprecable {
        // Note that Token(_token).approve(this, _amount) needs to be called
        // first or this contract will not be able to do the transfer.
        require(_token != 0);
        if (!Token(_token).transferFrom(msg.sender, this, _amount)) {
          revert();
        }
        tokens[_token][msg.sender] = safeAdd(tokens[_token][msg.sender], _amount);
        Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]);
      }
    
      function withdrawToken(address _token, uint _amount) {
        require(_token != 0);
        require(tokens[_token][msg.sender] >= _amount);
        tokens[_token][msg.sender] = safeSub(tokens[_token][msg.sender], _amount);
        if (!Token(_token).transfer(msg.sender, _amount)) {
          revert();
        }
        Withdraw(_token, msg.sender, _amount, tokens[_token][msg.sender]);
      }
    
      function balanceOf(address _token, address _user) constant returns (uint) {
        return tokens[_token][_user];
      }
      
      ////////////////////////////////////////////////////////////////////////////////
      // Trading
      ////////////////////////////////////////////////////////////////////////////////
    
      // Note: Order creation happens off-chain but the orders are signed by creators,
      // we validate the contents and the creator address in the logic below
    
      function trade(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive,
          uint _expires, uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s, uint _amount) {
        bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
        // Check order signatures and expiration, also check if not fulfilled yet
    		if (ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) != _user ||
          block.number > _expires ||
          safeAdd(orderFills[_user][hash], _amount) > _amountGet) {
          revert();
        }
        tradeBalances(_tokenGet, _amountGet, _tokenGive, _amountGive, _user, msg.sender, _amount);
        orderFills[_user][hash] = safeAdd(orderFills[_user][hash], _amount);
        Trade(_tokenGet, _amount, _tokenGive, _amountGive * _amount / _amountGet, _user, msg.sender, _nonce);
      }
      
      function tradeBalances(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive,
          address _user, address _caller, uint _amount) private {
    
        uint feeTakeValue = safeMul(_amount, fee) / (1 ether);
        uint rebateValue = 0;
        uint tokenGiveValue = safeMul(_amountGive, _amount) / _amountGet; // Proportionate to request ratio
    
        // Apply modifiers
        if (accountModifiers != address(0)) {
          var (feeTakeDiscount, rebatePercentage) = AccountModifiersInterface(accountModifiers).tradeModifiers(_user, _caller);
          // Check that the discounts/rebates are never higher then 100%
          if (feeTakeDiscount > 100) {
            feeTakeDiscount = 0;
          }
          if (rebatePercentage > 100) {
            rebatePercentage = 0;
          }
          feeTakeValue = safeMul(feeTakeValue, 100 - feeTakeDiscount) / 100;  // discounted fee
          rebateValue = safeMul(rebatePercentage, feeTakeValue) / 100;        // % of actual taker fee
        }
        
        tokens[_tokenGet][_user] = safeAdd(tokens[_tokenGet][_user], safeAdd(_amount, rebateValue));
        tokens[_tokenGet][_caller] = safeSub(tokens[_tokenGet][_caller], safeAdd(_amount, feeTakeValue));
        tokens[_tokenGive][_user] = safeSub(tokens[_tokenGive][_user], tokenGiveValue);
        tokens[_tokenGive][_caller] = safeAdd(tokens[_tokenGive][_caller], tokenGiveValue);
        tokens[_tokenGet][feeAccount] = safeAdd(tokens[_tokenGet][feeAccount], safeSub(feeTakeValue, rebateValue));
        
        if (tradeTracker != address(0)) {
          TradeTrackerInterface(tradeTracker).tradeComplete(_tokenGet, _amount, _tokenGive, tokenGiveValue, _user, _caller, feeTakeValue, rebateValue);
        }
      }
    
      function testTrade(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
          uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s, uint _amount, address _sender) constant returns(bool) {
        if (tokens[_tokenGet][_sender] < _amount ||
          availableVolume(_tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce, _user, _v, _r, _s) < _amount) {
          return false;
        }
        return true;
      }
    
      function availableVolume(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
          uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s) constant returns(uint) {
        bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
        if (ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) != _user ||
          block.number > _expires) {
          return 0;
        }
        uint available1 = safeSub(_amountGet, orderFills[_user][hash]);
        uint available2 = safeMul(tokens[_tokenGive][_user], _amountGet) / _amountGive;
        if (available1 < available2) return available1;
        return available2;
      }
    
      function amountFilled(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
          uint _nonce, address _user) constant returns(uint) {
        bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
        return orderFills[_user][hash];
      }
    
      function cancelOrder(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
          uint _nonce, uint8 _v, bytes32 _r, bytes32 _s) {
        bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
        if (!(ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) == msg.sender)) {
          revert();
        }
        orderFills[msg.sender][hash] = _amountGet;
        Cancel(_tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce, msg.sender, _v, _r, _s);
      }
      
      ////////////////////////////////////////////////////////////////////////////////
      // Migrations
      ////////////////////////////////////////////////////////////////////////////////
    
      // User-triggered (!) fund migrations in case contract got updated
      // Similar to withdraw but we use a successor account instead
      // As we don't store user tokens list on chain, it has to be passed from the outside
      function migrateFunds(address[] _tokens) {
      
        // Get the latest successor in the chain
        require(successor != address(0));
        TokenStore newExchange = TokenStore(successor);
        for (uint16 n = 0; n < 20; n++) {  // We will look past 20 contracts in the future
          address nextSuccessor = newExchange.successor();
          if (nextSuccessor == address(this)) {  // Circular succession
            revert();
          }
          if (nextSuccessor == address(0)) { // We reached the newest, stop
            break;
          }
          newExchange = TokenStore(nextSuccessor);
        }
    
        // Ether
        uint etherAmount = tokens[0][msg.sender];
        if (etherAmount > 0) {
          tokens[0][msg.sender] = 0;
          newExchange.depositForUser.value(etherAmount)(msg.sender);
        }
    
        // Tokens
        for (n = 0; n < _tokens.length; n++) {
          address token = _tokens[n];
          require(token != address(0)); // 0 = Ether, we handle it above
          uint tokenAmount = tokens[token][msg.sender];
          if (tokenAmount == 0) {
            continue;
          }
          if (!Token(token).approve(newExchange, tokenAmount)) {
            revert();
          }
          tokens[token][msg.sender] = 0;
          newExchange.depositTokenForUser(token, tokenAmount, msg.sender);
        }
    
        FundsMigrated(msg.sender);
      }
    
      // This is used for migrations only. To be called by previous exchange only,
      // user-triggered, on behalf of the user called the migrateFunds method.
      // Note that it does exactly the same as depositToken, but as this is called
      // by a previous generation of exchange itself, we credit internally not the
      // previous exchange, but the user it was called for.
      function depositForUser(address _user) payable deprecable {
        require(_user != address(0));
        require(msg.value > 0);
        TokenStore caller = TokenStore(msg.sender);
        require(caller.version() > 0); // Make sure it's an exchange account
        tokens[0][_user] = safeAdd(tokens[0][_user], msg.value);
      }
    
      function depositTokenForUser(address _token, uint _amount, address _user) deprecable {
        require(_token != address(0));
        require(_user != address(0));
        require(_amount > 0);
        TokenStore caller = TokenStore(msg.sender);
        require(caller.version() > 0); // Make sure it's an exchange account
        if (!Token(_token).transferFrom(msg.sender, this, _amount)) {
          revert();
        }
        tokens[_token][_user] = safeAdd(tokens[_token][_user], _amount);
      }
    }

    File 2 of 2: FiCoin
    pragma solidity ^0.4.18;
    
    contract OraclizeI {
        address public cbAddress;
        function query(uint _timestamp, string _datasource, string _arg) external payable returns (bytes32 _id);
        function query_withGasLimit(uint _timestamp, string _datasource, string _arg, uint _gaslimit) external payable returns (bytes32 _id);
        function query2(uint _timestamp, string _datasource, string _arg1, string _arg2) public payable returns (bytes32 _id);
        function query2_withGasLimit(uint _timestamp, string _datasource, string _arg1, string _arg2, uint _gaslimit) external payable returns (bytes32 _id);
        function queryN(uint _timestamp, string _datasource, bytes _argN) public payable returns (bytes32 _id);
        function queryN_withGasLimit(uint _timestamp, string _datasource, bytes _argN, uint _gaslimit) external payable returns (bytes32 _id);
        function getPrice(string _datasource) public returns (uint _dsprice);
        function getPrice(string _datasource, uint gaslimit) public returns (uint _dsprice);
        function setProofType(byte _proofType) external;
        function setCustomGasPrice(uint _gasPrice) external;
        function randomDS_getSessionPubKeyHash() external constant returns(bytes32);
    }
    contract OraclizeAddrResolverI {
        function getAddress() public returns (address _addr);
    }
    contract usingOraclize {
        uint constant day = 60*60*24;
        uint constant week = 60*60*24*7;
        uint constant month = 60*60*24*30;
        byte constant proofType_NONE = 0x00;
        byte constant proofType_TLSNotary = 0x10;
        byte constant proofType_Android = 0x20;
        byte constant proofType_Ledger = 0x30;
        byte constant proofType_Native = 0xF0;
        byte constant proofStorage_IPFS = 0x01;
        uint8 constant networkID_auto = 0;
        uint8 constant networkID_mainnet = 1;
        uint8 constant networkID_testnet = 2;
        uint8 constant networkID_morden = 2;
        uint8 constant networkID_consensys = 161;
    
        OraclizeAddrResolverI OAR;
    
        OraclizeI oraclize;
        modifier oraclizeAPI {
            if((address(OAR)==0)||(getCodeSize(address(OAR))==0))
                oraclize_setNetwork(networkID_auto);
    
            if(address(oraclize) != OAR.getAddress())
                oraclize = OraclizeI(OAR.getAddress());
    
            _;
        }
        modifier coupon(string code){
            oraclize = OraclizeI(OAR.getAddress());
            _;
        }
    
        function oraclize_setNetwork(uint8 networkID) internal returns(bool){
          return oraclize_setNetwork();
          networkID; // silence the warning and remain backwards compatible
        }
        function oraclize_setNetwork() internal returns(bool){
            if (getCodeSize(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed)>0){ //mainnet
                OAR = OraclizeAddrResolverI(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed);
                oraclize_setNetworkName("eth_mainnet");
                return true;
            }
            if (getCodeSize(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1)>0){ //ropsten testnet
                OAR = OraclizeAddrResolverI(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1);
                oraclize_setNetworkName("eth_ropsten3");
                return true;
            }
            if (getCodeSize(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e)>0){ //kovan testnet
                OAR = OraclizeAddrResolverI(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e);
                oraclize_setNetworkName("eth_kovan");
                return true;
            }
            if (getCodeSize(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48)>0){ //rinkeby testnet
                OAR = OraclizeAddrResolverI(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48);
                oraclize_setNetworkName("eth_rinkeby");
                return true;
            }
            if (getCodeSize(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475)>0){ //ethereum-bridge
                OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475);
                return true;
            }
            if (getCodeSize(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF)>0){ //ether.camp ide
                OAR = OraclizeAddrResolverI(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF);
                return true;
            }
            if (getCodeSize(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA)>0){ //browser-solidity
                OAR = OraclizeAddrResolverI(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA);
                return true;
            }
            return false;
        }
    
        function __callback(bytes32 myid, string result) public {
            __callback(myid, result, new bytes(0));
        }
        function __callback(bytes32 myid, string result, bytes proof) public {
          return;
          myid; result; proof; // Silence compiler warnings
        }
    
        function oraclize_getPrice(string datasource) oraclizeAPI internal returns (uint){
            return oraclize.getPrice(datasource);
        }
    
        function oraclize_getPrice(string datasource, uint gaslimit) oraclizeAPI internal returns (uint){
            return oraclize.getPrice(datasource, gaslimit);
        }
    
        function oraclize_query(string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
            return oraclize.query.value(price)(0, datasource, arg);
        }
        function oraclize_query(uint timestamp, string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
            return oraclize.query.value(price)(timestamp, datasource, arg);
        }
        function oraclize_query(uint timestamp, string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
            return oraclize.query_withGasLimit.value(price)(timestamp, datasource, arg, gaslimit);
        }
        function oraclize_query(string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
            return oraclize.query_withGasLimit.value(price)(0, datasource, arg, gaslimit);
        }
        function oraclize_query(string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
            return oraclize.query2.value(price)(0, datasource, arg1, arg2);
        }
        function oraclize_query(uint timestamp, string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
            return oraclize.query2.value(price)(timestamp, datasource, arg1, arg2);
        }
        function oraclize_query(uint timestamp, string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
            return oraclize.query2_withGasLimit.value(price)(timestamp, datasource, arg1, arg2, gaslimit);
        }
        function oraclize_query(string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
            return oraclize.query2_withGasLimit.value(price)(0, datasource, arg1, arg2, gaslimit);
        }
        function oraclize_query(string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
            bytes memory args = stra2cbor(argN);
            return oraclize.queryN.value(price)(0, datasource, args);
        }
        function oraclize_query(uint timestamp, string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
            bytes memory args = stra2cbor(argN);
            return oraclize.queryN.value(price)(timestamp, datasource, args);
        }
        function oraclize_query(uint timestamp, string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
            bytes memory args = stra2cbor(argN);
            return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
        }
        function oraclize_query(string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
            bytes memory args = stra2cbor(argN);
            return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
        }
        function oraclize_query(string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](1);
            dynargs[0] = args[0];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](1);
            dynargs[0] = args[0];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](1);
            dynargs[0] = args[0];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](1);
            dynargs[0] = args[0];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
    
        function oraclize_query(string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
    
        function oraclize_query(string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[] argN) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
            bytes memory args = ba2cbor(argN);
            return oraclize.queryN.value(price)(0, datasource, args);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[] argN) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
            bytes memory args = ba2cbor(argN);
            return oraclize.queryN.value(price)(timestamp, datasource, args);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
            bytes memory args = ba2cbor(argN);
            return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
        }
        function oraclize_query(string datasource, bytes[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
            bytes memory args = ba2cbor(argN);
            return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
        }
        function oraclize_query(string datasource, bytes[1] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](1);
            dynargs[0] = args[0];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[1] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](1);
            dynargs[0] = args[0];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](1);
            dynargs[0] = args[0];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](1);
            dynargs[0] = args[0];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
    
        function oraclize_query(string datasource, bytes[2] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[2] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[3] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[3] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
    
        function oraclize_query(string datasource, bytes[4] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[4] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[5] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[5] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
    
        function oraclize_cbAddress() oraclizeAPI internal returns (address){
            return oraclize.cbAddress();
        }
        function oraclize_setProof(byte proofP) oraclizeAPI internal {
            return oraclize.setProofType(proofP);
        }
        function oraclize_setCustomGasPrice(uint gasPrice) oraclizeAPI internal {
            return oraclize.setCustomGasPrice(gasPrice);
        }
    
        function oraclize_randomDS_getSessionPubKeyHash() oraclizeAPI internal returns (bytes32){
            return oraclize.randomDS_getSessionPubKeyHash();
        }
    
        function getCodeSize(address _addr) constant internal returns(uint _size) {
            assembly {
                _size := extcodesize(_addr)
            }
        }
    
        function parseAddr(string _a) internal pure returns (address){
            bytes memory tmp = bytes(_a);
            uint160 iaddr = 0;
            uint160 b1;
            uint160 b2;
            for (uint i=2; i<2+2*20; i+=2){
                iaddr *= 256;
                b1 = uint160(tmp[i]);
                b2 = uint160(tmp[i+1]);
                if ((b1 >= 97)&&(b1 <= 102)) b1 -= 87;
                else if ((b1 >= 65)&&(b1 <= 70)) b1 -= 55;
                else if ((b1 >= 48)&&(b1 <= 57)) b1 -= 48;
                if ((b2 >= 97)&&(b2 <= 102)) b2 -= 87;
                else if ((b2 >= 65)&&(b2 <= 70)) b2 -= 55;
                else if ((b2 >= 48)&&(b2 <= 57)) b2 -= 48;
                iaddr += (b1*16+b2);
            }
            return address(iaddr);
        }
    
        function strCompare(string _a, string _b) internal pure returns (int) {
            bytes memory a = bytes(_a);
            bytes memory b = bytes(_b);
            uint minLength = a.length;
            if (b.length < minLength) minLength = b.length;
            for (uint i = 0; i < minLength; i ++)
                if (a[i] < b[i])
                    return -1;
                else if (a[i] > b[i])
                    return 1;
            if (a.length < b.length)
                return -1;
            else if (a.length > b.length)
                return 1;
            else
                return 0;
        }
    
        function indexOf(string _haystack, string _needle) internal pure returns (int) {
            bytes memory h = bytes(_haystack);
            bytes memory n = bytes(_needle);
            if(h.length < 1 || n.length < 1 || (n.length > h.length))
                return -1;
            else if(h.length > (2**128 -1))
                return -1;
            else
            {
                uint subindex = 0;
                for (uint i = 0; i < h.length; i ++)
                {
                    if (h[i] == n[0])
                    {
                        subindex = 1;
                        while(subindex < n.length && (i + subindex) < h.length && h[i + subindex] == n[subindex])
                        {
                            subindex++;
                        }
                        if(subindex == n.length)
                            return int(i);
                    }
                }
                return -1;
            }
        }
    
        function strConcat(string _a, string _b, string _c, string _d, string _e) internal pure returns (string) {
            bytes memory _ba = bytes(_a);
            bytes memory _bb = bytes(_b);
            bytes memory _bc = bytes(_c);
            bytes memory _bd = bytes(_d);
            bytes memory _be = bytes(_e);
            string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
            bytes memory babcde = bytes(abcde);
            uint k = 0;
            for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
            for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
            for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
            for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
            for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
            return string(babcde);
        }
    
        function strConcat(string _a, string _b, string _c, string _d) internal pure returns (string) {
            return strConcat(_a, _b, _c, _d, "");
        }
    
        function strConcat(string _a, string _b, string _c) internal pure returns (string) {
            return strConcat(_a, _b, _c, "", "");
        }
    
        function strConcat(string _a, string _b) internal pure returns (string) {
            return strConcat(_a, _b, "", "", "");
        }
    
        // parseInt
        function parseInt(string _a) internal pure returns (uint) {
            return parseInt(_a, 0);
        }
    
        // parseInt(parseFloat*10^_b)
        function parseInt(string _a, uint _b) internal pure returns (uint) {
            bytes memory bresult = bytes(_a);
            uint mint = 0;
            bool decimals = false;
            for (uint i=0; i<bresult.length; i++){
                if ((bresult[i] >= 48)&&(bresult[i] <= 57)){
                    if (decimals){
                       if (_b == 0) break;
                        else _b--;
                    }
                    mint *= 10;
                    mint += uint(bresult[i]) - 48;
                } else if (bresult[i] == 46) decimals = true;
            }
            if (_b > 0) mint *= 10**_b;
            return mint;
        }
    
        function uint2str(uint i) internal pure returns (string){
            if (i == 0) return "0";
            uint j = i;
            uint len;
            while (j != 0){
                len++;
                j /= 10;
            }
            bytes memory bstr = new bytes(len);
            uint k = len - 1;
            while (i != 0){
                bstr[k--] = byte(48 + i % 10);
                i /= 10;
            }
            return string(bstr);
        }
    
        function stra2cbor(string[] arr) internal pure returns (bytes) {
                uint arrlen = arr.length;
    
                // get correct cbor output length
                uint outputlen = 0;
                bytes[] memory elemArray = new bytes[](arrlen);
                for (uint i = 0; i < arrlen; i++) {
                    elemArray[i] = (bytes(arr[i]));
                    outputlen += elemArray[i].length + (elemArray[i].length - 1)/23 + 3; //+3 accounts for paired identifier types
                }
                uint ctr = 0;
                uint cborlen = arrlen + 0x80;
                outputlen += byte(cborlen).length;
                bytes memory res = new bytes(outputlen);
    
                while (byte(cborlen).length > ctr) {
                    res[ctr] = byte(cborlen)[ctr];
                    ctr++;
                }
                for (i = 0; i < arrlen; i++) {
                    res[ctr] = 0x5F;
                    ctr++;
                    for (uint x = 0; x < elemArray[i].length; x++) {
                        // if there's a bug with larger strings, this may be the culprit
                        if (x % 23 == 0) {
                            uint elemcborlen = elemArray[i].length - x >= 24 ? 23 : elemArray[i].length - x;
                            elemcborlen += 0x40;
                            uint lctr = ctr;
                            while (byte(elemcborlen).length > ctr - lctr) {
                                res[ctr] = byte(elemcborlen)[ctr - lctr];
                                ctr++;
                            }
                        }
                        res[ctr] = elemArray[i][x];
                        ctr++;
                    }
                    res[ctr] = 0xFF;
                    ctr++;
                }
                return res;
            }
    
        function ba2cbor(bytes[] arr) internal pure returns (bytes) {
                uint arrlen = arr.length;
    
                // get correct cbor output length
                uint outputlen = 0;
                bytes[] memory elemArray = new bytes[](arrlen);
                for (uint i = 0; i < arrlen; i++) {
                    elemArray[i] = (bytes(arr[i]));
                    outputlen += elemArray[i].length + (elemArray[i].length - 1)/23 + 3; //+3 accounts for paired identifier types
                }
                uint ctr = 0;
                uint cborlen = arrlen + 0x80;
                outputlen += byte(cborlen).length;
                bytes memory res = new bytes(outputlen);
    
                while (byte(cborlen).length > ctr) {
                    res[ctr] = byte(cborlen)[ctr];
                    ctr++;
                }
                for (i = 0; i < arrlen; i++) {
                    res[ctr] = 0x5F;
                    ctr++;
                    for (uint x = 0; x < elemArray[i].length; x++) {
                        // if there's a bug with larger strings, this may be the culprit
                        if (x % 23 == 0) {
                            uint elemcborlen = elemArray[i].length - x >= 24 ? 23 : elemArray[i].length - x;
                            elemcborlen += 0x40;
                            uint lctr = ctr;
                            while (byte(elemcborlen).length > ctr - lctr) {
                                res[ctr] = byte(elemcborlen)[ctr - lctr];
                                ctr++;
                            }
                        }
                        res[ctr] = elemArray[i][x];
                        ctr++;
                    }
                    res[ctr] = 0xFF;
                    ctr++;
                }
                return res;
            }
    
    
        string oraclize_network_name;
        function oraclize_setNetworkName(string _network_name) internal {
            oraclize_network_name = _network_name;
        }
    
        function oraclize_getNetworkName() internal view returns (string) {
            return oraclize_network_name;
        }
    
        function oraclize_newRandomDSQuery(uint _delay, uint _nbytes, uint _customGasLimit) internal returns (bytes32){
            require((_nbytes > 0) && (_nbytes <= 32));
            bytes memory nbytes = new bytes(1);
            nbytes[0] = byte(_nbytes);
            bytes memory unonce = new bytes(32);
            bytes memory sessionKeyHash = new bytes(32);
            bytes32 sessionKeyHash_bytes32 = oraclize_randomDS_getSessionPubKeyHash();
            assembly {
                mstore(unonce, 0x20)
                mstore(add(unonce, 0x20), xor(blockhash(sub(number, 1)), xor(coinbase, timestamp)))
                mstore(sessionKeyHash, 0x20)
                mstore(add(sessionKeyHash, 0x20), sessionKeyHash_bytes32)
            }
            bytes[3] memory args = [unonce, nbytes, sessionKeyHash];
            bytes32 queryId = oraclize_query(_delay, "random", args, _customGasLimit);
            oraclize_randomDS_setCommitment(queryId, keccak256(bytes8(_delay), args[1], sha256(args[0]), args[2]));
            return queryId;
        }
    
        function oraclize_randomDS_setCommitment(bytes32 queryId, bytes32 commitment) internal {
            oraclize_randomDS_args[queryId] = commitment;
        }
    
        mapping(bytes32=>bytes32) oraclize_randomDS_args;
        mapping(bytes32=>bool) oraclize_randomDS_sessionKeysHashVerified;
    
        function verifySig(bytes32 tosignh, bytes dersig, bytes pubkey) internal returns (bool){
            bool sigok;
            address signer;
    
            bytes32 sigr;
            bytes32 sigs;
    
            bytes memory sigr_ = new bytes(32);
            uint offset = 4+(uint(dersig[3]) - 0x20);
            sigr_ = copyBytes(dersig, offset, 32, sigr_, 0);
            bytes memory sigs_ = new bytes(32);
            offset += 32 + 2;
            sigs_ = copyBytes(dersig, offset+(uint(dersig[offset-1]) - 0x20), 32, sigs_, 0);
    
            assembly {
                sigr := mload(add(sigr_, 32))
                sigs := mload(add(sigs_, 32))
            }
    
    
            (sigok, signer) = safer_ecrecover(tosignh, 27, sigr, sigs);
            if (address(keccak256(pubkey)) == signer) return true;
            else {
                (sigok, signer) = safer_ecrecover(tosignh, 28, sigr, sigs);
                return (address(keccak256(pubkey)) == signer);
            }
        }
    
        function oraclize_randomDS_proofVerify__sessionKeyValidity(bytes proof, uint sig2offset) internal returns (bool) {
            bool sigok;
    
            // Step 6: verify the attestation signature, APPKEY1 must sign the sessionKey from the correct ledger app (CODEHASH)
            bytes memory sig2 = new bytes(uint(proof[sig2offset+1])+2);
            copyBytes(proof, sig2offset, sig2.length, sig2, 0);
    
            bytes memory appkey1_pubkey = new bytes(64);
            copyBytes(proof, 3+1, 64, appkey1_pubkey, 0);
    
            bytes memory tosign2 = new bytes(1+65+32);
            tosign2[0] = byte(1); //role
            copyBytes(proof, sig2offset-65, 65, tosign2, 1);
            bytes memory CODEHASH = hex"fd94fa71bc0ba10d39d464d0d8f465efeef0a2764e3887fcc9df41ded20f505c";
            copyBytes(CODEHASH, 0, 32, tosign2, 1+65);
            sigok = verifySig(sha256(tosign2), sig2, appkey1_pubkey);
    
            if (sigok == false) return false;
    
    
            // Step 7: verify the APPKEY1 provenance (must be signed by Ledger)
            bytes memory LEDGERKEY = hex"7fb956469c5c9b89840d55b43537e66a98dd4811ea0a27224272c2e5622911e8537a2f8e86a46baec82864e98dd01e9ccc2f8bc5dfc9cbe5a91a290498dd96e4";
    
            bytes memory tosign3 = new bytes(1+65);
            tosign3[0] = 0xFE;
            copyBytes(proof, 3, 65, tosign3, 1);
    
            bytes memory sig3 = new bytes(uint(proof[3+65+1])+2);
            copyBytes(proof, 3+65, sig3.length, sig3, 0);
    
            sigok = verifySig(sha256(tosign3), sig3, LEDGERKEY);
    
            return sigok;
        }
    
        modifier oraclize_randomDS_proofVerify(bytes32 _queryId, string _result, bytes _proof) {
            // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1)
            require((_proof[0] == "L") && (_proof[1] == "P") && (_proof[2] == 1));
    
            bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName());
            require(proofVerified);
    
            _;
        }
    
        function oraclize_randomDS_proofVerify__returnCode(bytes32 _queryId, string _result, bytes _proof) internal returns (uint8){
            // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1)
            if ((_proof[0] != "L")||(_proof[1] != "P")||(_proof[2] != 1)) return 1;
    
            bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName());
            if (proofVerified == false) return 2;
    
            return 0;
        }
    
        function matchBytes32Prefix(bytes32 content, bytes prefix, uint n_random_bytes) internal pure returns (bool){
            bool match_ = true;
            
    
            for (uint256 i=0; i< n_random_bytes; i++) {
                if (content[i] != prefix[i]) match_ = false;
            }
    
            return match_;
        }
    
        function oraclize_randomDS_proofVerify__main(bytes proof, bytes32 queryId, bytes result, string context_name) internal returns (bool){
    
            // Step 2: the unique keyhash has to match with the sha256 of (context name + queryId)
            uint ledgerProofLength = 3+65+(uint(proof[3+65+1])+2)+32;
            bytes memory keyhash = new bytes(32);
            copyBytes(proof, ledgerProofLength, 32, keyhash, 0);
            if (!(keccak256(keyhash) == keccak256(sha256(context_name, queryId)))) return false;
    
            bytes memory sig1 = new bytes(uint(proof[ledgerProofLength+(32+8+1+32)+1])+2);
            copyBytes(proof, ledgerProofLength+(32+8+1+32), sig1.length, sig1, 0);
    
            // Step 3: we assume sig1 is valid (it will be verified during step 5) and we verify if 'result' is the prefix of sha256(sig1)
            if (!matchBytes32Prefix(sha256(sig1), result, uint(proof[ledgerProofLength+32+8]))) return false;
    
            // Step 4: commitment match verification, keccak256(delay, nbytes, unonce, sessionKeyHash) == commitment in storage.
            // This is to verify that the computed args match with the ones specified in the query.
            bytes memory commitmentSlice1 = new bytes(8+1+32);
            copyBytes(proof, ledgerProofLength+32, 8+1+32, commitmentSlice1, 0);
    
            bytes memory sessionPubkey = new bytes(64);
            uint sig2offset = ledgerProofLength+32+(8+1+32)+sig1.length+65;
            copyBytes(proof, sig2offset-64, 64, sessionPubkey, 0);
    
            bytes32 sessionPubkeyHash = sha256(sessionPubkey);
            if (oraclize_randomDS_args[queryId] == keccak256(commitmentSlice1, sessionPubkeyHash)){ //unonce, nbytes and sessionKeyHash match
                delete oraclize_randomDS_args[queryId];
            } else return false;
    
    
            // Step 5: validity verification for sig1 (keyhash and args signed with the sessionKey)
            bytes memory tosign1 = new bytes(32+8+1+32);
            copyBytes(proof, ledgerProofLength, 32+8+1+32, tosign1, 0);
            if (!verifySig(sha256(tosign1), sig1, sessionPubkey)) return false;
    
            // verify if sessionPubkeyHash was verified already, if not.. let's do it!
            if (oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash] == false){
                oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash] = oraclize_randomDS_proofVerify__sessionKeyValidity(proof, sig2offset);
            }
    
            return oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash];
        }
    
        // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
        function copyBytes(bytes from, uint fromOffset, uint length, bytes to, uint toOffset) internal pure returns (bytes) {
            uint minLength = length + toOffset;
    
            // Buffer too small
            require(to.length >= minLength); // Should be a better way?
    
            // NOTE: the offset 32 is added to skip the `size` field of both bytes variables
            uint i = 32 + fromOffset;
            uint j = 32 + toOffset;
    
            while (i < (32 + fromOffset + length)) {
                assembly {
                    let tmp := mload(add(from, i))
                    mstore(add(to, j), tmp)
                }
                i += 32;
                j += 32;
            }
    
            return to;
        }
    
        // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
        // Duplicate Solidity's ecrecover, but catching the CALL return value
        function safer_ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal returns (bool, address) {
            // We do our own memory management here. Solidity uses memory offset
            // 0x40 to store the current end of memory. We write past it (as
            // writes are memory extensions), but don't update the offset so
            // Solidity will reuse it. The memory used here is only needed for
            // this context.
    
            // FIXME: inline assembly can't access return values
            bool ret;
            address addr;
    
            assembly {
                let size := mload(0x40)
                mstore(size, hash)
                mstore(add(size, 32), v)
                mstore(add(size, 64), r)
                mstore(add(size, 96), s)
    
                // NOTE: we can reuse the request memory because we deal with
                //       the return code
                ret := call(3000, 1, 0, size, 128, size, 32)
                addr := mload(size)
            }
    
            return (ret, addr);
        }
    
        // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
        function ecrecovery(bytes32 hash, bytes sig) internal returns (bool, address) {
            bytes32 r;
            bytes32 s;
            uint8 v;
    
            if (sig.length != 65)
              return (false, 0);
    
            // The signature format is a compact form of:
            //   {bytes32 r}{bytes32 s}{uint8 v}
            // Compact means, uint8 is not padded to 32 bytes.
            assembly {
                r := mload(add(sig, 32))
                s := mload(add(sig, 64))
    
                // Here we are loading the last 32 bytes. We exploit the fact that
                // 'mload' will pad with zeroes if we overread.
                // There is no 'mload8' to do this, but that would be nicer.
                v := byte(0, mload(add(sig, 96)))
    
                // Alternative solution:
                // 'byte' is not working due to the Solidity parser, so lets
                // use the second best option, 'and'
                // v := and(mload(add(sig, 65)), 255)
            }
    
            // albeit non-transactional signatures are not specified by the YP, one would expect it
            // to match the YP range of [27, 28]
            //
            // geth uses [0, 1] and some clients have followed. This might change, see:
            //  https://github.com/ethereum/go-ethereum/issues/2053
            if (v < 27)
              v += 27;
    
            if (v != 27 && v != 28)
                return (false, 0);
    
            return safer_ecrecover(hash, v, r, s);
        }
    
    }
    // </ORACLIZE_API>
    
    library SafeMath {
      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
          return 0;
        }
        uint256 c = a * b;
        assert(c / a == b);
        return c;
      }
    
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return c;
      }
    
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
      }
    
      function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
      }
    }
    
    contract ERC20 {
        uint256 public totalSupply;
        function balanceOf(address who) public view returns (uint256);
        function transfer(address to, uint256 value) public returns (bool);
        function transferFrom(address from, address to, uint256 value) public returns (bool);
        function allowance(address owner, address spender) public view returns (uint256);
        function approve(address spender, uint256 value) public returns (bool);
        event Approval(address indexed owner, address indexed spender, uint256 value);
        event Transfer(address indexed from, address indexed to, uint256 value);
    }
    
    contract StandardToken is ERC20 {
        using SafeMath for uint256;
    
        mapping(address => uint256) balances;
        mapping (address => mapping (address => uint256)) internal allowed;
    
        /**
        * @dev Gets the balance of the specified address.
        * @param _owner The address to query the the balance of.
        * @return An uint256 representing the amount owned by the passed address.
        */
        function balanceOf(address _owner) public view returns (uint256 balance) {
            return balances[_owner];
        }
    
        /**
        * @dev transfer token for a specified address
        * @param _to The address to transfer to.
        * @param _value The amount to be transferred.
        */
        function transfer(address _to, uint256 _value) public returns (bool) {
            require(_to != address(0));
            require(_value <= balances[msg.sender]);
    
            // SafeMath.sub will throw if there is not enough balance.
            balances[msg.sender] = balances[msg.sender].sub(_value);
            balances[_to] = balances[_to].add(_value);
            Transfer(msg.sender, _to, _value);
            return true;
        }
    
        /**
        * @dev Transfer tokens from one address to another
        * @param _from address The address which you want to send tokens from
        * @param _to address The address which you want to transfer to
        * @param _value uint256 the amount of tokens to be transferred
        */
        function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
            require(_to != address(0));
            require(_value <= balances[_from]);
            require(_value <= allowed[_from][msg.sender]);
    
            balances[_from] = balances[_from].sub(_value);
            balances[_to] = balances[_to].add(_value);
            allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
            Transfer(_from, _to, _value);
            return true;
        }
    
        /**
        * @dev Function to check the amount of tokens that an owner allowed to a spender.
        * @param _owner address The address which owns the funds.
        * @param _spender address The address which will spend the funds.
        * @return A uint256 specifying the amount of tokens still available for the spender.
        */
        function allowance(address _owner, address _spender) public view returns (uint256) {
            return allowed[_owner][_spender];
        }
    
        /**
        * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
        *
        * Beware that changing an allowance with this method brings the risk that someone may use both the old
        * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
        * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
        * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
        * @param _spender The address which will spend the funds.
        * @param _value The amount of tokens to be spent.
        */
        function approve(address _spender, uint256 _value) public returns (bool) {
            allowed[msg.sender][_spender] = _value;
            Approval(msg.sender, _spender, _value);
            return true;
        }
    
    
        /**
        * approve should be called when allowed[_spender] == 0. To increment
        * allowed value is better to use this function to avoid 2 calls (and wait until
        * the first transaction is mined)
        * From MonolithDAO Token.sol
        */
        function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
            allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
            Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
            return true;
        }
    
        function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
            uint oldValue = allowed[msg.sender][_spender];
            if (_subtractedValue > oldValue) {
            allowed[msg.sender][_spender] = 0;
            } else {
            allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
            }
            Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
            return true;
        }
    }
    
    contract FiCoin is StandardToken, usingOraclize {
    
        using SafeMath for uint256;
    
        struct Contributor {
            address addr;
            uint256 amount;
        }
    
        mapping (bytes32 => Contributor) internal contributors;
    
        //==========================================================
        // TOKEN PROPERTIES
        //==========================================================
        string public constant name = "FiCoin";
        string public constant symbol = "FiC";
        uint256 public constant decimals = 18;
        string public version = "1.0";
    
        //==========================================================
        // STAGE LIMITS PROPERTIES
        //==========================================================
        uint256 public saleCap;
    
        //==========================================================
        // WALLETS
        //==========================================================
        address public FiCoinFundDeposit;
        address public CoinStorage;
        address public OwnerAddress;
    
        //==========================================================
        // CROWDSALE STAGES
        //==========================================================
        bool internal isPreSale = false;
        bool internal isFirstRound  = false;
        bool internal isSecondRound = false;
    
        uint256 public burnedTokens;
    
        //==========================================================
        // INTERNAL VARIABLES
        //==========================================================
        uint256 internal tokenPriceInCents;
        uint256 internal buyLimit;
        uint256 internal totalLocked;
        uint256 internal startDate;
        uint256 internal endDate;
        mapping(address => uint256) internal lockedTokens;
        mapping(address => uint256) internal buyLimitPerAddress;
    
        //==========================================================
        // EVENTS
        //==========================================================
        event OraclizeQuery(string description);
        event Burn(address indexed burner, uint256 value);
        event TokenPurchase(address indexed purchaser, uint256 value, uint256 amount);
        event Lock(address indexed purchaser, uint256 value);
    
        //==========================================================
        // MODIFIERS
        //==========================================================
        modifier onlyOwner() {
            require(msg.sender == OwnerAddress);
            _;
        }
    
        //==========================================================
        // CONSTRUCTOR
        //==========================================================
        function FiCoin() public {
    
            FiCoinFundDeposit = 0x00aa6ddfa8ADD5B1E6bCfFcbaB83c3FDBd10DA91;
            CoinStorage = 0x00aD59ec96C12dA4C4546383fac422fEF45a21bB;
            OwnerAddress = 0x00aD59ec96C12dA4C4546383fac422fEF45a21bB;
            
            totalSupply = 14930352 * 10 ** decimals;
    
            // crowdsale statistics
            tokenPriceInCents = 34;
            buyLimit = 0;
            saleCap = 0;
    
            // burned tokens
            burnedTokens = 0;
    
            // move the supply the storage
            balances[CoinStorage] = totalSupply;
    
            startDate = 0;
            endDate = 0;
        }
    
        //==========================================================
        // ONLY OWNER FUNCTIONS
        //==========================================================
        function forwardFunds() onlyOwner public {
            FiCoinFundDeposit.transfer(this.balance);
        }
    
        //==========================================================
        // PUBLIC FUNCTIONS
        //==========================================================
        function () public payable {
            buyTokens(msg.sender);
        }
    
        // low level token purchase function
        function buyTokens(address beneficiary) public payable {
            require(beneficiary != address(0));
            require(msg.value >= 1 * 10 ** 17); // minimum ETH contribution is 0.1 ETH
            require(startDate < now && endDate > now);
            
            // this functionallity is kept in the same function with purpose.
            if (oraclize_getPrice("URL") > this.balance) {
                OraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee");
            } else {
                OraclizeQuery("Oraclize query was sent, standing by for the answer.");
                bytes32 queryId = oraclize_query("URL", "json(https://api.coinmarketcap.com/v1/ticker/ethereum).0.price_usd");
                contributors[queryId] = Contributor(beneficiary, msg.value);
            }
        }
        
        function lockedOf(address _owner) public view returns (uint256 locked) {
            return lockedTokens[_owner];
        }
        
        function __callback(bytes32 myid, string result, bytes proof) public {
            require (msg.sender == oraclize_cbAddress());
    
            uint256 etherPrice = parseInt(result, 2);
            uint256 purchasedTokens = getPurchasedTokens(contributors[myid].amount, etherPrice);
        
            privateTransfer(contributors[myid].addr, purchasedTokens);
            TokenPurchase(contributors[myid].addr, contributors[myid].amount, purchasedTokens);
    
            delete contributors[myid];
        }
    
    
        //==========================================================
        // INTERNAL FUNCTIONS
        //==========================================================
        function getPurchasedTokens(uint256 _weiAmount, uint256 _etherPrice) internal constant returns (uint256) { 
            require(_etherPrice > 0);
    
            //Formula:
            //( weiAmount * etherPrice (cents) ) / ( tokenPrice (cents) )
            uint256 purchasedTokens = _weiAmount.mul(_etherPrice);
            purchasedTokens = purchasedTokens.div(tokenPriceInCents);
    
            return purchasedTokens;
        }
    
        function privateTransfer(address _to, uint256 _value) internal returns (bool) {
            require(_to != address(0));
            require(_value <= balances[CoinStorage]);
            // check that sold tokens + purchase value + totalLocked is less than the saleCap
            require(totalSupply - balances[CoinStorage] + _value + totalLocked <= saleCap);
            // check that user's locked tokens + purchase value is less than the purchase limit
            require(buyLimitPerAddress[_to] + lockedTokens[_to] + _value <= buyLimit); 
    
            // SafeMath.sub will throw if there is not enough balance.
            balances[CoinStorage] = balances[CoinStorage].sub(_value);
            balances[_to] = balances[_to].add(_value);
            //===================================================================
            buyLimitPerAddress[_to] = buyLimitPerAddress[_to].add(_value);
            //===================================================================
            Transfer(CoinStorage, _to, _value);
            return true;
        }
    
        // Add to totalLocked
        // Substract from owner's balance
        // Init mapping.
        function lock(address _to, uint256 _value) onlyOwner public {
            require(_to != address(0));
            require(_value <= balances[CoinStorage]);
            // check that sold tokens + purchase value + totalLocked is less than the saleCap
            require(totalSupply - balances[CoinStorage] + _value + totalLocked <= saleCap);
            // check that user's locked tokens + purchase value is less than the purchase limit
            require(buyLimitPerAddress[_to] + lockedTokens[_to] + _value <= buyLimit);
            
            totalLocked = totalLocked + _value;
            balances[CoinStorage] = balances[CoinStorage].sub(_value);
            lockedTokens[_to] = _value;
        }
    
        // Unlock tokens
        // Transfer tokens
        function pay(address _to, uint256 _value) onlyOwner public {
            unlock(_to);
            privateTransfer(_to, _value);
        }
    
        // Substract from totalLocked
        // Add the locked tokens to the owner's balance
        // Delete mapping element
        function unlock(address _to) onlyOwner public {
            require(_to != address(0));
            require(lockedTokens[_to] > 0);
    
            totalLocked = totalLocked.sub(lockedTokens[_to]);
            balances[CoinStorage] = balances[CoinStorage].add(lockedTokens[_to]);
            delete lockedTokens[_to];
        }
    
    
        //==========================================================
        // EXTERNAL FUNCTIONS
        //==========================================================
        function switchSaleStage() onlyOwner public {
            require(!isSecondRound);
    
            if (!isPreSale) {
                isPreSale = true;
                tokenPriceInCents = 34;
                buyLimit = 5000 * 10 ** decimals;
                saleCap = 2178309 * 10 ** decimals;
            } else if (!isFirstRound) {
                isFirstRound = true;
                tokenPriceInCents = 55;
                buyLimit = buyLimit + 10000 * 10 ** decimals;
                saleCap = totalSupply - balances[CoinStorage] + 3524578 * 10 ** decimals;
            } else if (!isSecondRound) {
                isSecondRound = true;
                tokenPriceInCents = 89;
                buyLimit = buyLimit + 15000 * 10**decimals;
                saleCap = totalSupply - balances[CoinStorage] + 5702887 * 10 ** decimals;
            } 
    
            startDate = now + 1 minutes;
            endDate = startDate + 120 hours;
        }
        
        /**
         * @dev Burns a specific amount of tokens.
         * @param _value The amount of token to be burned.
         */
        function burn(uint256 _value) public {
            require(_value > 0);
            require(_value <= balances[msg.sender]);
            // no need to require value <= totalSupply, since that would imply the
            // sender's balance is greater than the totalSupply, which *should* be an assertion failure
    
            address burner = msg.sender;
            balances[burner] = balances[burner].sub(_value);
            totalSupply = totalSupply.sub(_value);
            burnedTokens = burnedTokens.add(_value);
            Burn(burner, _value);
        }
    }