github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/cmd/mist/assets/ext/ethereum.js/lib/abi.js (about)

     1  /*
     2      This file is part of ethereum.js.
     3  
     4      ethereum.js is free software: you can redistribute it and/or modify
     5      it under the terms of the GNU Lesser General Public License as published by
     6      the Free Software Foundation, either version 3 of the License, or
     7      (at your option) any later version.
     8  
     9      ethereum.js is distributed in the hope that it will be useful,
    10      but WITHOUT ANY WARRANTY; without even the implied warranty of
    11      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12      GNU Lesser General Public License for more details.
    13  
    14      You should have received a copy of the GNU Lesser General Public License
    15      along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.
    16  */
    17  /** @file abi.js
    18   * @authors:
    19   *   Marek Kotewicz <marek@ethdev.com>
    20   *   Gav Wood <g@ethdev.com>
    21   * @date 2014
    22   */
    23  
    24  var web3 = require('./web3'); 
    25  var utils = require('./utils');
    26  var types = require('./types');
    27  var c = require('./const');
    28  var f = require('./formatters');
    29  
    30  var displayTypeError = function (type) {
    31      console.error('parser does not support type: ' + type);
    32  };
    33  
    34  /// This method should be called if we want to check if givent type is an array type
    35  /// @returns true if it is, otherwise false
    36  var arrayType = function (type) {
    37      return type.slice(-2) === '[]';
    38  };
    39  
    40  var dynamicTypeBytes = function (type, value) {
    41      // TODO: decide what to do with array of strings
    42      if (arrayType(type) || type === 'string')    // only string itself that is dynamic; stringX is static length.
    43          return f.formatInputInt(value.length); 
    44      return "";
    45  };
    46  
    47  var inputTypes = types.inputTypes(); 
    48  
    49  /// Formats input params to bytes
    50  /// @param abi contract method inputs
    51  /// @param array of params that will be formatted to bytes
    52  /// @returns bytes representation of input params
    53  var formatInput = function (inputs, params) {
    54      var bytes = "";
    55      var padding = c.ETH_PADDING * 2;
    56  
    57      /// first we iterate in search for dynamic 
    58      inputs.forEach(function (input, index) {
    59          bytes += dynamicTypeBytes(input.type, params[index]);
    60      });
    61  
    62      inputs.forEach(function (input, i) {
    63          var typeMatch = false;
    64          for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
    65              typeMatch = inputTypes[j].type(inputs[i].type, params[i]);
    66          }
    67          if (!typeMatch) {
    68              displayTypeError(inputs[i].type);
    69          }
    70  
    71          var formatter = inputTypes[j - 1].format;
    72          var toAppend = "";
    73  
    74          if (arrayType(inputs[i].type))
    75              toAppend = params[i].reduce(function (acc, curr) {
    76                  return acc + formatter(curr);
    77              }, "");
    78          else
    79              toAppend = formatter(params[i]);
    80  
    81          bytes += toAppend; 
    82      });
    83      return bytes;
    84  };
    85  
    86  var dynamicBytesLength = function (type) {
    87      if (arrayType(type) || type === 'string')   // only string itself that is dynamic; stringX is static length.
    88          return c.ETH_PADDING * 2;
    89      return 0;
    90  };
    91  
    92  var outputTypes = types.outputTypes(); 
    93  
    94  /// Formats output bytes back to param list
    95  /// @param contract abi method outputs
    96  /// @param bytes representtion of output 
    97  /// @returns array of output params 
    98  var formatOutput = function (outs, output) {
    99      
   100      output = output.slice(2);
   101      var result = [];
   102      var padding = c.ETH_PADDING * 2;
   103  
   104      var dynamicPartLength = outs.reduce(function (acc, curr) {
   105          return acc + dynamicBytesLength(curr.type);
   106      }, 0);
   107      
   108      var dynamicPart = output.slice(0, dynamicPartLength);
   109      output = output.slice(dynamicPartLength);
   110  
   111      outs.forEach(function (out, i) {
   112          var typeMatch = false;
   113          for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
   114              typeMatch = outputTypes[j].type(outs[i].type);
   115          }
   116  
   117          if (!typeMatch) {
   118              displayTypeError(outs[i].type);
   119          }
   120  
   121          var formatter = outputTypes[j - 1].format;
   122          if (arrayType(outs[i].type)) {
   123              var size = f.formatOutputUInt(dynamicPart.slice(0, padding));
   124              dynamicPart = dynamicPart.slice(padding);
   125              var array = [];
   126              for (var k = 0; k < size; k++) {
   127                  array.push(formatter(output.slice(0, padding))); 
   128                  output = output.slice(padding);
   129              }
   130              result.push(array);
   131          }
   132          else if (types.prefixedType('string')(outs[i].type)) {
   133              dynamicPart = dynamicPart.slice(padding); 
   134              result.push(formatter(output.slice(0, padding)));
   135              output = output.slice(padding);
   136          } else {
   137              result.push(formatter(output.slice(0, padding)));
   138              output = output.slice(padding);
   139          }
   140      });
   141  
   142      return result;
   143  };
   144  
   145  /// @param json abi for contract
   146  /// @returns input parser object for given json abi
   147  /// TODO: refactor creating the parser, do not double logic from contract
   148  var inputParser = function (json) {
   149      var parser = {};
   150      json.forEach(function (method) {
   151          var displayName = utils.extractDisplayName(method.name); 
   152          var typeName = utils.extractTypeName(method.name);
   153  
   154          var impl = function () {
   155              var params = Array.prototype.slice.call(arguments);
   156              return formatInput(method.inputs, params);
   157          };
   158         
   159          if (parser[displayName] === undefined) {
   160              parser[displayName] = impl;
   161          }
   162  
   163          parser[displayName][typeName] = impl;
   164      });
   165  
   166      return parser;
   167  };
   168  
   169  /// @param json abi for contract
   170  /// @returns output parser for given json abi
   171  var outputParser = function (json) {
   172      var parser = {};
   173      json.forEach(function (method) {
   174  
   175          var displayName = utils.extractDisplayName(method.name); 
   176          var typeName = utils.extractTypeName(method.name);
   177  
   178          var impl = function (output) {
   179              return formatOutput(method.outputs, output);
   180          };
   181  
   182          if (parser[displayName] === undefined) {
   183              parser[displayName] = impl;
   184          }
   185  
   186          parser[displayName][typeName] = impl;
   187      });
   188  
   189      return parser;
   190  };
   191  
   192  /// @param function/event name for which we want to get signature
   193  /// @returns signature of function/event with given name
   194  var signatureFromAscii = function (name) {
   195      return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);
   196  };
   197  
   198  var eventSignatureFromAscii = function (name) {
   199      return web3.sha3(web3.fromAscii(name));
   200  };
   201  
   202  module.exports = {
   203      inputParser: inputParser,
   204      outputParser: outputParser,
   205      formatInput: formatInput,
   206      formatOutput: formatOutput,
   207      signatureFromAscii: signatureFromAscii,
   208      eventSignatureFromAscii: eventSignatureFromAscii
   209  };
   210