@ -28,20 +28,8 @@ var types = require('./types');
var c = require ( './const' ) ;
var f = require ( './formatters' ) ;
/// Filters all function from input abi
/// @returns abi array with filtered objects of type 'function'
var filterFunctions = function ( json ) {
return json . filter ( function ( current ) {
return current . type === 'function' ;
} ) ;
} ;
/// Filters all events form input abi
/// @returns abi array with filtered objects of type 'event'
var filterEvents = function ( json ) {
return json . filter ( function ( current ) {
return current . type === 'event' ;
} ) ;
var displayTypeError = function ( type ) {
console . error ( 'parser does not support type: ' + type ) ;
} ;
/// This method should be called if we want to check if givent type is an array type
@ -60,31 +48,31 @@ var dynamicTypeBytes = function (type, value) {
var inputTypes = types . inputTypes ( ) ;
/// Formats input params to bytes
/// @param abi contract method
/// @param abi contract method inputs
/// @param array of params that will be formatted to bytes
/// @returns bytes representation of input params
var toAbi Input = function ( method , params ) {
var forma tInput = function ( inputs , params ) {
var bytes = "" ;
var padding = c . ETH_PADDING * 2 ;
/// first we iterate in search for dynamic
method . inputs . forEach ( function ( input , index ) {
inputs . forEach ( function ( input , index ) {
bytes += dynamicTypeBytes ( input . type , params [ index ] ) ;
} ) ;
method . inputs . forEach ( function ( input , i ) {
inputs . forEach ( function ( input , i ) {
var typeMatch = false ;
for ( var j = 0 ; j < inputTypes . length && ! typeMatch ; j ++ ) {
typeMatch = inputTypes [ j ] . type ( method . inputs [ i ] . type , params [ i ] ) ;
typeMatch = inputTypes [ j ] . type ( inputs [ i ] . type , params [ i ] ) ;
}
if ( ! typeMatch ) {
console . error ( 'input parser does not support type: ' + method . inputs [ i ] . type ) ;
displayTypeError ( inputs [ i ] . type ) ;
}
var formatter = inputTypes [ j - 1 ] . format ;
var toAppend = "" ;
if ( arrayType ( method . inputs [ i ] . type ) )
if ( arrayType ( inputs [ i ] . type ) )
toAppend = params [ i ] . reduce ( function ( acc , curr ) {
return acc + formatter ( curr ) ;
} , "" ) ;
@ -105,34 +93,34 @@ var dynamicBytesLength = function (type) {
var outputTypes = types . outputTypes ( ) ;
/// Formats output bytes back to param list
/// @param contract abi method
/// @param contract abi method outputs
/// @param bytes representtion of output
/// @returns array of output params
var fromAbi Output = function ( method , output ) {
var format Output = function ( outs , output ) {
output = output . slice ( 2 ) ;
var result = [ ] ;
var padding = c . ETH_PADDING * 2 ;
var dynamicPartLength = meth od . outp uts. reduce ( function ( acc , curr ) {
var dynamicPartLength = outs . reduce ( function ( acc , curr ) {
return acc + dynamicBytesLength ( curr . type ) ;
} , 0 ) ;
var dynamicPart = output . slice ( 0 , dynamicPartLength ) ;
output = output . slice ( dynamicPartLength ) ;
meth od . outp uts. forEach ( function ( out , i ) {
outs . forEach ( function ( out , i ) {
var typeMatch = false ;
for ( var j = 0 ; j < outputTypes . length && ! typeMatch ; j ++ ) {
typeMatch = outputTypes [ j ] . type ( meth od . outp uts[ i ] . type ) ;
typeMatch = outputTypes [ j ] . type ( outs [ i ] . type ) ;
}
if ( ! typeMatch ) {
console . error ( 'output parser does not support type: ' + method . outp uts[ i ] . type ) ;
displayTypeError ( o uts[ i ] . type ) ;
}
var formatter = outputTypes [ j - 1 ] . format ;
if ( arrayType ( meth od . outp uts[ i ] . type ) ) {
if ( arrayType ( outs [ i ] . type ) ) {
var size = f . formatOutputUInt ( dynamicPart . slice ( 0 , padding ) ) ;
dynamicPart = dynamicPart . slice ( padding ) ;
var array = [ ] ;
@ -142,7 +130,7 @@ var fromAbiOutput = function (method, output) {
}
result . push ( array ) ;
}
else if ( types . prefixedType ( 'string' ) ( meth od . outp uts[ i ] . type ) ) {
else if ( types . prefixedType ( 'string' ) ( outs [ i ] . type ) ) {
dynamicPart = dynamicPart . slice ( padding ) ;
result . push ( formatter ( output . slice ( 0 , padding ) ) ) ;
output = output . slice ( padding ) ;
@ -155,31 +143,18 @@ var fromAbiOutput = function (method, output) {
return result ;
} ;
/// @returns display name for method eg. multiply(uint256) -> multiply
var methodDisplayName = function ( method ) {
var length = method . indexOf ( '(' ) ;
return length !== - 1 ? method . substr ( 0 , length ) : method ;
} ;
/// @returns overloaded part of method's name
var methodTypeName = function ( method ) {
/// TODO: make it invulnerable
var length = method . indexOf ( '(' ) ;
return length !== - 1 ? method . substr ( length + 1 , method . length - 1 - ( length + 1 ) ) : "" ;
} ;
/// @param json abi for contract
/// @returns input parser object for given json abi
/// TODO: refactor creating the parser, do not double logic from contract
var inputParser = function ( json ) {
var parser = { } ;
json . forEach ( function ( method ) {
var displayName = method DisplayName( method . name ) ;
var typeName = method TypeName( method . name ) ;
var displayName = utils . extractDisplayName ( method . name ) ;
var typeName = utils . extractTypeName ( method . name ) ;
var impl = function ( ) {
var params = Array . prototype . slice . call ( arguments ) ;
return toAbi Input ( method , params ) ;
return formatInput ( method . inputs , params ) ;
} ;
if ( parser [ displayName ] === undefined ) {
@ -198,11 +173,11 @@ var outputParser = function (json) {
var parser = { } ;
json . forEach ( function ( method ) {
var displayName = method DisplayName( method . name ) ;
var typeName = method TypeName( method . name ) ;
var displayName = utils . extract DisplayName( method . name ) ;
var typeName = utils . extract TypeName( method . name ) ;
var impl = function ( output ) {
return fromAbi Output ( method , output ) ;
return format Output ( method . outputs , output ) ;
} ;
if ( parser [ displayName ] === undefined ) {
@ -215,20 +190,18 @@ var outputParser = function (json) {
return parser ;
} ;
/// @param method name for which we want to get method signature
/// @returns (promise) contract method signature for method with given name
var methodSignature = function ( name ) {
return web3 . sha3 ( web3 . fromAscii ( name ) ) . slice ( 0 , 2 + c . ETH_METHOD_ SIGNATURE_LENGTH * 2 ) ;
/// @param function/event name for which we want to get signature
/// @returns signature of function/event with given name
var signatureFromAscii = function ( name ) {
return web3 . sha3 ( web3 . fromAscii ( name ) ) . slice ( 0 , 2 + c . ETH_SIGNATURE_LENGTH * 2 ) ;
} ;
module . exports = {
inputParser : inputParser ,
outputParser : outputParser ,
methodSignature : methodSignature ,
methodDisplayName : methodDisplayName ,
methodTypeName : methodTypeName ,
filterFunctions : filterFunctions ,
filterEvents : filterEvents
formatInput : formatInput ,
formatOutput : formatOutput ,
signatureFromAscii : signatureFromAscii
} ;
@ -262,7 +235,7 @@ if ("build" !== 'build') {/*
module . exports = {
ETH_PADDING : 32 ,
ETH_METHOD_ SIGNATURE_LENGTH : 4 ,
ETH_SIGNATURE_LENGTH : 4 ,
ETH_BIGNUMBER_ROUNDING_MODE : { ROUNDING_MODE : BigNumber . ROUND_DOWN }
} ;
@ -292,8 +265,18 @@ module.exports = {
var web3 = require ( './web3' ) ;
var abi = require ( './abi' ) ;
var utils = require ( './utils' ) ;
var eventImpl = require ( './event' ) ;
var exportNatspecGlobals = function ( vars ) {
// it's used byt natspec.js
// TODO: figure out better way to solve this
web3 . _ currentContractAbi = vars . abi ;
web3 . _ currentContractAddress = vars . address ;
web3 . _ currentContractMethodName = vars . method ;
web3 . _ currentContractMethodParams = vars . params ;
} ;
var addFunctionRelatedPropertiesToContract = function ( contract ) {
contract . call = function ( options ) {
@ -323,14 +306,14 @@ var addFunctionsToContract = function (contract, desc, address) {
var outputParser = abi . outputParser ( desc ) ;
// create contract functions
abi . filterFunctions ( desc ) . forEach ( function ( method ) {
utils . filterFunctions ( desc ) . forEach ( function ( method ) {
var displayName = abi . method DisplayName( method . name ) ;
var typeName = abi . method TypeName( method . name ) ;
var displayName = utils . extract DisplayName( method . name ) ;
var typeName = utils . extract TypeName( method . name ) ;
var impl = function ( ) {
var params = Array . prototype . slice . call ( arguments ) ;
var signature = abi . methodSignature ( method . name ) ;
var signature = abi . signatureFromAscii ( method . name ) ;
var parsed = inputParser [ displayName ] [ typeName ] . apply ( null , params ) ;
var options = contract . _ options || { } ;
@ -345,12 +328,13 @@ var addFunctionsToContract = function (contract, desc, address) {
contract . _ isTransact = null ;
if ( isTransact ) {
// it's used byt natspec.js
// TODO: figure out better way to solve this
web3 . _ currentContractAbi = desc ;
web3 . _ currentContractAddress = address ;
web3 . _ currentContractMethodName = method . name ;
web3 . _ currentContractMethodParams = params ;
exportNatspecGlobals ( {
abi : desc ,
address : address ,
method : method . name ,
params : params
} ) ;
// transactions do not have any output, cause we do not know, when they will be processed
web3 . eth . transact ( options ) ;
@ -382,8 +366,8 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) {
Object . defineProperty ( contract , 'topic' , {
get : function ( ) {
return abi . filterEvents ( desc ) . map ( function ( e ) {
return abi . methodSignature ( e . name ) ;
return utils . filterEvents ( desc ) . map ( function ( e ) {
return abi . signatureFromAscii ( e . name ) ;
} ) ;
}
} ) ;
@ -392,11 +376,11 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) {
var addEventsToContract = function ( contract , desc , address ) {
// create contract events
abi . filterEvents ( desc ) . forEach ( function ( e ) {
utils . filterEvents ( desc ) . forEach ( function ( e ) {
var impl = function ( ) {
var params = Array . prototype . slice . call ( arguments ) ;
var signature = abi . methodSignature ( e . name ) ;
var signature = abi . signatureFromAscii ( e . name ) ;
var event = eventImpl ( address , signature , e ) ;
var o = event . apply ( null , params ) ;
return web3 . eth . watch ( o ) ;
@ -405,18 +389,8 @@ var addEventsToContract = function (contract, desc, address) {
// this property should be used by eth.filter to check if object is an event
impl . _ isEvent = true ;
// TODO: we can remove address && topic properties, they are not used anymore since we introduced _isEvent
impl . address = address ;
Object . defineProperty ( impl , 'topic' , {
get : function ( ) {
return [ abi . methodSignature ( e . name ) ] ;
}
} ) ;
// TODO: rename these methods, cause they are used not only for methods
var displayName = abi . methodDisplayName ( e . name ) ;
var typeName = abi . methodTypeName ( e . name ) ;
var displayName = utils . extractDisplayName ( e . name ) ;
var typeName = utils . extractTypeName ( e . name ) ;
if ( contract [ displayName ] === undefined ) {
contract [ displayName ] = impl ;
@ -476,7 +450,7 @@ var contract = function (address, desc) {
module . exports = contract ;
} , { "./abi" : 1 , "./event" : 4 , "./web3" : 12 } ] , 4 : [ function ( require , module , exports ) {
} , { "./abi" : 1 , "./event" : 4 , "./utils" : 11 , "./ web3" : 12 } ] , 4 : [ function ( require , module , exports ) {
/ *
This file is part of ethereum . js .
@ -508,7 +482,7 @@ var inputWithName = function (inputs, name) {
} ) ;
if ( index === - 1 ) {
console . error ( 'indexed paray with name ' + name + ' not found' ) ;
console . error ( 'indexed param with name ' + name + ' not found' ) ;
return undefined ;
}
return inputs [ index ] ;
@ -517,19 +491,15 @@ var inputWithName = function (inputs, name) {
var indexedParamsToTopics = function ( event , indexed ) {
// sort keys?
return Object . keys ( indexed ) . map ( function ( key ) {
// TODO: simplify this!
var parser = abi . inputParser ( [ {
name : 'test' ,
inputs : [ inputWithName ( event . inputs , key ) ]
} ] ) ;
var inputs = [ inputWithName ( event . inputs , key ) ] ;
var value = indexed [ key ] ;
if ( value instanceof Array ) {
return value . map ( function ( v ) {
return parser . test ( v ) ;
return abi . formatInput ( inputs , [ v ] ) ;
} ) ;
}
return parser . test ( value ) ;
return abi . formatInput ( inputs , [ value ] ) ;
} ) ;
} ;
@ -1178,11 +1148,43 @@ var fromAscii = function(str, pad) {
return "0x" + hex ;
} ;
/// @returns display name for function/event eg. multiply(uint256) -> multiply
var extractDisplayName = function ( name ) {
var length = name . indexOf ( '(' ) ;
return length !== - 1 ? name . substr ( 0 , length ) : name ;
} ;
/// @returns overloaded part of function/event name
var extractTypeName = function ( name ) {
/// TODO: make it invulnerable
var length = name . indexOf ( '(' ) ;
return length !== - 1 ? name . substr ( length + 1 , name . length - 1 - ( length + 1 ) ) : "" ;
} ;
/// Filters all function from input abi
/// @returns abi array with filtered objects of type 'function'
var filterFunctions = function ( json ) {
return json . filter ( function ( current ) {
return current . type === 'function' ;
} ) ;
} ;
/// Filters all events form input abi
/// @returns abi array with filtered objects of type 'event'
var filterEvents = function ( json ) {
return json . filter ( function ( current ) {
return current . type === 'event' ;
} ) ;
} ;
module . exports = {
findIndex : findIndex ,
toAscii : toAscii ,
fromAscii : fromAscii
fromAscii : fromAscii ,
extractDisplayName : extractDisplayName ,
extractTypeName : extractTypeName ,
filterFunctions : filterFunctions ,
filterEvents : filterEvents
} ;