diff --git a/abi2sol/lib/abi2sol.rb b/abi2sol/lib/abi2sol.rb index f866ac5..4bf039f 100644 --- a/abi2sol/lib/abi2sol.rb +++ b/abi2sol/lib/abi2sol.rb @@ -4,10 +4,12 @@ ## our own code +require_relative 'abi2sol/model' require_relative 'abi2sol/generate' + module Abi2Sol class Tool diff --git a/abi2sol/lib/abi2sol/generate.rb b/abi2sol/lib/abi2sol/generate.rb index 09998b9..fb6c0f0 100644 --- a/abi2sol/lib/abi2sol/generate.rb +++ b/abi2sol/lib/abi2sol/generate.rb @@ -16,6 +16,16 @@ def generate_interface( name: ) ## interface declarations # buf << "#{@ctor.decl}\n" # end + + if events.size > 0 + buf << "\n" + buf << "// #{events.size} Event(s)\n" + events.each do |event| + buf << "#{event.decl}\n" + end + end + + if payable_functions.size > 0 buf << "\n" buf << "// #{payable_functions.size} Payable Function(s)\n" diff --git a/abi2sol/lib/abi2sol/model.rb b/abi2sol/lib/abi2sol/model.rb new file mode 100644 index 0000000..1d56231 --- /dev/null +++ b/abi2sol/lib/abi2sol/model.rb @@ -0,0 +1,76 @@ + +module ABI + +class Param + def decl + buf = String.new('') + buf << "#{sig} " + buf << "indexed " if @indexed + buf << (@name ? @name : '_') + ## use inline comment - why? why not? + if @internal_type && @internal_type != sig + buf << " /* #{@internal_type} */" + end + buf + end +end ## class Param + + +class Constructor + def decl + buf = "constructor" + if @inputs.empty? + buf << "()" + else + params = @inputs.map {|param| param.decl } + buf << "(#{params.join(', ')})" + end + buf << ";" + buf + end +end ## class Constructor + +class Function + def decl + buf = "function #{@name}" + if @inputs.empty? + buf << "()" + else + params = @inputs.map {|param| param.decl } + buf << "(#{params.join(', ')})" + end + buf << " payable " if @payable + buf << " view " if @constant && !@pure + buf << " pure " if @constant && @pure + + if @outputs.empty? + ## do nothing + else + buf << " returns " + params = @outputs.map {|param| param.decl } + buf << "(#{params.join(', ')})" + end + buf << ";" + buf + end +end ## class Function + + +class Event + def decl + buf = "event #{@name}" + if @inputs.empty? + buf << "()" + else + params = @inputs.map {|param| param.decl } + buf << "(#{params.join(', ')})" + end + buf << ";" + buf + end +end ## class Event + + + + +end ## module ABI diff --git a/abi2sol/sandbox/test_parse.rb b/abi2sol/sandbox/test_parse.rb index 8357d96..e67abb8 100644 --- a/abi2sol/sandbox/test_parse.rb +++ b/abi2sol/sandbox/test_parse.rb @@ -2,6 +2,7 @@ # to run use # ruby -I ./lib sandbox/test_parse.rb +$LOAD_PATH.unshift( "../abiparser/lib" ) require 'abi2sol' diff --git a/abi2sol/sandbox/test_parse2.rb b/abi2sol/sandbox/test_parse2.rb new file mode 100644 index 0000000..cd5a14f --- /dev/null +++ b/abi2sol/sandbox/test_parse2.rb @@ -0,0 +1,23 @@ +### +# to run use +# ruby -I ./lib sandbox/test_parse2.rb + +$LOAD_PATH.unshift( "../abiparser/lib" ) +require 'abi2sol' + +names = [ + 'AirSwap', + 'BunchaStructs', +] + +names.each do |name| + abi = ABI.read( "./abis//#{name}.abi.json" ) + pp abi + + buf = abi.generate_interface( name: name ) + puts buf + write_text( "./tmp/#{name}.sol", buf ) +end + + +puts "bye" diff --git a/abiparser/lib/abiparser.rb b/abiparser/lib/abiparser.rb index 52cd2be..048c596 100644 --- a/abiparser/lib/abiparser.rb +++ b/abiparser/lib/abiparser.rb @@ -44,6 +44,7 @@ def sig( bin ) require_relative 'abiparser/param' require_relative 'abiparser/constructor' require_relative 'abiparser/function' +require_relative 'abiparser/event' require_relative 'abiparser/utils' require_relative 'abiparser/contract' require_relative 'abiparser/interface' diff --git a/abiparser/lib/abiparser/constructor.rb b/abiparser/lib/abiparser/constructor.rb index 702a37d..a8f037a 100644 --- a/abiparser/lib/abiparser/constructor.rb +++ b/abiparser/lib/abiparser/constructor.rb @@ -20,7 +20,7 @@ def self.parse( o ) pp o end - if o.has_key?( 'constant') + if o.has_key?( 'constant' ) puts "!! WARN: constant for constructor possible?" pp o exit 1 @@ -95,19 +95,6 @@ def doc buf end - def decl - buf = "constructor" - if @inputs.empty? - buf << "()" - else - buf2 = @inputs.map {|param| param.decl } - buf << "(#{buf2.join(', ')})" - end - buf << ";" - buf - end - - end # class Constructor end # module ABI diff --git a/abiparser/lib/abiparser/contract.rb b/abiparser/lib/abiparser/contract.rb index 6054a79..66f9cd1 100644 --- a/abiparser/lib/abiparser/contract.rb +++ b/abiparser/lib/abiparser/contract.rb @@ -15,6 +15,7 @@ def self.parse( data ) funcs = [] has_fallback = false has_receive = true + events = [] data.each do |o| if o['type'] == 'function' @@ -23,6 +24,7 @@ def self.parse( data ) raise ArgumentError, "constructor already defined; only one declaration allowed" if ctor ctor = Constructor.parse( o ) elsif o['type'] == 'event' + events << Event.parse( o ) elsif o['type'] == 'receive' ## skip for now ## e.g. @@ -46,7 +48,7 @@ def self.parse( data ) end new( constructor: ctor, functions: funcs, - events: [], + events: events, has_receive: has_receive, has_fallback: has_fallback ) end @@ -96,6 +98,8 @@ def support?( sig ) def constructor() @ctor; end def functions() @funcs; end + def events() @events; end + ### ## how to name functions categories ??? diff --git a/abiparser/lib/abiparser/event.rb b/abiparser/lib/abiparser/event.rb new file mode 100644 index 0000000..75e4e4b --- /dev/null +++ b/abiparser/lib/abiparser/event.rb @@ -0,0 +1,56 @@ +module ABI + class Event + + def self.parse( o ) + ## todo/fix: assert type function (or contructor) ?? + name = o['name'] + inputs = o['inputs'].map {|param| Param.parse( param ) } + + new( name, inputs: inputs ) + end + + + attr_reader :name, + :inputs + ## :input_types + + def initialize( name, + inputs: [] ) + @name = name + @inputs = inputs + end + + + def sig + ## note: signature + ## only includes name and inputs + + ## + ## todo/fix: check if event sig includes indexed or/and + ## special prefix or such!!!! + + buf = "#{@name}" + if @inputs.empty? + buf << "()" + else + params = @inputs.map {|param| param.sig } + buf << "(#{params.join(',')})" + end + buf + end + + def sighash + keccak256( sig )[0,4].hexdigest + end + + + + + def types + ## for debugging / analytics return all used types (input+output) + @inputs.map {|param| param.type } + end + + end ## class Event + end ## module ABI + diff --git a/abiparser/lib/abiparser/function.rb b/abiparser/lib/abiparser/function.rb index 2de6c99..554a9cb 100644 --- a/abiparser/lib/abiparser/function.rb +++ b/abiparser/lib/abiparser/function.rb @@ -134,29 +134,6 @@ def doc buf end - def decl - buf = "function #{@name}" - if @inputs.empty? - buf << "()" - else - buf2 = @inputs.map {|param| param.decl } - buf << "(#{buf2.join(', ')})" - end - buf << " payable " if @payable - buf << " view " if @constant && !@pure - buf << " pure " if @constant && @pure - - if @outputs.empty? - ## do nothing - else - buf << " returns " - buf2 = @outputs.map {|param| param.decl } - buf << "(#{buf2.join(', ')})" - end - buf << ";" - buf - end - def types ## for debugging / analytics return all used types (input+output) diff --git a/abiparser/lib/abiparser/param.rb b/abiparser/lib/abiparser/param.rb index 93664a0..ad3f060 100644 --- a/abiparser/lib/abiparser/param.rb +++ b/abiparser/lib/abiparser/param.rb @@ -9,17 +9,20 @@ def self.parse( o ) internal_type = o['internalType'] name = o['name'] components = o['components'] ? o['components'].map { |c| parse( c ) } : nil + indexed = o['indexed'] new( type, name, internal_type: internal_type, - components: components ) + components: components, + indexed: indexed ) end ### check - find a "better" name for internal_type ## use a keyword param - why? why not? def initialize( type, name=nil, internal_type: nil, - components: nil ) ## note: type goes first!!! + components: nil, + indexed: nil ) ## note: type goes first!!! @type = type ## note: convert empty string "" to nil - why? why not? @name = if name && name.empty? @@ -33,9 +36,11 @@ def initialize( type, name=nil, internal_type end @components = components + @indexed = indexed ## note: only used for event params (create a subparam type - why? why not??) end + def sig @sig ||= begin if @components @@ -62,17 +67,5 @@ def doc buf end - def decl - buf = '' - buf << "#{sig} " - buf << (@name ? @name : '_') - ## use inline comment - why? why not? - if @internal_type && @internal_type != sig - buf << " /* #{@internal_type} */" - end - buf - end - - end ## class Param end ## module ABI