abiparser 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77899a7da00b8be7b61c97d2f1ebad297a6d33f74bd081c59b17f8b66bca78f1
4
- data.tar.gz: 15a102dc8505eb359fcb5d117de026e9308641e714ea50096895ee15fb4d655e
3
+ metadata.gz: 9f938a2858e7da14cc5a8b42f4691a93c4721cef9e271168de78535c64f70115
4
+ data.tar.gz: 8450885be9f443548be957d0815bb31e3c56862f0368eb17f574ab176ea9e4b0
5
5
  SHA512:
6
- metadata.gz: 2bf5a3d5928df6f9d5a650f50ca05df22edb82f0d305a5ef66c552b36fee9b33d6166b63dfd4e878c8a32f7a86e042517159cc6b0155cf96734b36a0ab596817
7
- data.tar.gz: 8181ddd11ad89481204f1796ef4eebc854d10ec83fb8cd6d3fd45ce8da830cff2fd1273c726c507853843442c174c603bd66fcb735ae4aabf433141827befebb
6
+ metadata.gz: bc52799f38979a1e8b77b21d711e0ff935510ce7988bdec34e5ad0a09a5dde8db522df3038808f165dcd4178051ef49f7f832d1b76fc9fac0ef5c4f3331fd92b
7
+ data.tar.gz: 6a6d1e03041d70e7080c38ad3e534c5e57a0cd49af187c4a16dfe1f19ae7fa55d4c8a3068b12968dd64a3d23f3c08c8f4c5fd47ac96e83f9bc7da695e0dfef7b
data/Manifest.txt CHANGED
@@ -7,5 +7,7 @@ lib/abiparser/constructor.rb
7
7
  lib/abiparser/contract.rb
8
8
  lib/abiparser/export/interface.rb
9
9
  lib/abiparser/function.rb
10
+ lib/abiparser/interface.rb
10
11
  lib/abiparser/param.rb
12
+ lib/abiparser/utils.rb
11
13
  lib/abiparser/version.rb
data/README.md CHANGED
@@ -13,6 +13,133 @@ abiparser - application binary interface (abi) parser machinery / helper for Eth
13
13
  ## Usage
14
14
 
15
15
 
16
+ ### Functions Signature Hashes / Selectors & Interface (Type) Ids
17
+
18
+
19
+ You can calculate the function selectors (or "sighash",
20
+ that is, signature hash)
21
+ by hashing the function signature
22
+ e.g. `supportsInterface(bytes4)` with the Keccak 256-Bit algorithm
23
+ and than use the first 4 bytes, that is, `0x01ffc9a7` (out of 32 bytes),
24
+ that is, `0x01ffc9a7a5cef8baa21ed3c5c0d7e23accb804b619e9333b597f47a0d84076e2`. Example:
25
+
26
+
27
+ ``` ruby
28
+ require 'abiparser'
29
+
30
+ sig = 'supportsInterface(bytes4)'
31
+ pp keccak256( sig )[0,4].hexdigest
32
+ #=> "0x01ffc9a7"
33
+ ```
34
+
35
+ Note: The `String#hexdigest` (also known as `String#bin_to_hex`) helper
36
+ converts a binary string (with `BINARY`/`ASCII-8BIT` encoding)
37
+ into a hex(adecimal) string.
38
+
39
+
40
+ You can calcuate interface (type) ids
41
+ by xor-ing (`^`) together the sighashes.
42
+ If the interface only has one function than
43
+ the interface (type) id equals the function sighash (by definition).
44
+
45
+
46
+ ``` solidity
47
+ interface ERC165 {
48
+ /// @notice Query if a contract implements an interface
49
+ /// @param interfaceID The interface identifier, as specified in ERC-165
50
+ /// @dev Interface identification is specified in ERC-165.
51
+ /// @return `true` if the contract implements `interfaceID` and
52
+ /// `interfaceID` is not 0xffffffff, `false` otherwise
53
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
54
+ }
55
+ // The interface identifier for this interface is 0x01ffc9a7.
56
+ ```
57
+
58
+ If you check the sighash for `supportsInterface(bytes4)`,
59
+ that is, `0x01ffc9a7` (see above)
60
+ than - bingo! - the interface id for ERC165 matches up.
61
+
62
+
63
+ Let's try to calculate the ERC20 standard (fungible) token interface
64
+ where the official id is `0x36372b07` by xor-ing (`^`) together all function sighashes:
65
+
66
+ ``` ruby
67
+ pp (keccak256('totalSupply()')[0,4] ^
68
+ keccak256('balanceOf(address)')[0,4] ^
69
+ keccak256('allowance(address,address)')[0,4] ^
70
+ keccak256('transfer(address,uint256)')[0,4] ^
71
+ keccak256('approve(address,uint256)')[0,4] ^
72
+ keccak256('transferFrom(address,address,uint256)')[0,4]).hexdigest
73
+ #=> "0x36372b07"
74
+
75
+ # or where def sig(bin) = keccak256(bin)[0,4])
76
+
77
+ pp (sig('totalSupply()') ^
78
+ sig('balanceOf(address)') ^
79
+ sig('allowance(address,address)') ^
80
+ sig('transfer(address,uint256)') ^
81
+ sig('approve(address,uint256)') ^
82
+ sig('transferFrom(address,address,uint256)')).hexdigest
83
+ #=> "0x36372b07"
84
+ ```
85
+
86
+ Voila!
87
+ Or re(use) the builtin pre-defined interfaces. Example:
88
+
89
+ ``` ruby
90
+ pp IERC165.inteface_id #=> "0x01ffc9a7"
91
+ pp IERC20.interface_id #=> "0x36372b07"
92
+ pp IERC721.interface_id #=> "0x80ac58cd"
93
+ pp IERC721_METADATA.interface_id #=> "0x5b5e139f"
94
+ pp IERC721_ENUMERABLE.interface_id #=> "0x780e9d63"
95
+ ```
96
+
97
+ Yes, you can. Define your own interface. Let's have a looksie
98
+ at the built-ins. Example:
99
+
100
+ ``` ruby
101
+ IERC165 = ABI::Interface.new(
102
+ 'supportsInterface(bytes4)'
103
+ )
104
+
105
+ IERC20 = ABI::Interface.new(
106
+ 'totalSupply()',
107
+ 'balanceOf(address)',
108
+ 'allowance(address,address)',
109
+ 'transfer(address,uint256)',
110
+ 'approve(address,uint256)',
111
+ 'transferFrom(address,address,uint256)'
112
+ )
113
+
114
+ IERC721 = ABI::Interface.new(
115
+ 'balanceOf(address)',
116
+ 'ownerOf(uint256)',
117
+ 'approve(address,uint256)',
118
+ 'getApproved(uint256)',
119
+ 'setApprovalForAll(address,bool)',
120
+ 'isApprovedForAll(address,address)',
121
+ 'transferFrom(address,address,uint256)',
122
+ 'safeTransferFrom(address,address,uint256)',
123
+ 'safeTransferFrom(address,address,uint256,bytes)' )
124
+
125
+ IERC721_METADATA = ABI::Interface.new(
126
+ 'name()',
127
+ 'symbol()',
128
+ 'tokenURI(uint256)' )
129
+
130
+ IERC721_ENUMERABLE = ABI::Interface.new(
131
+ 'tokenOfOwnerByIndex(address,uint256)',
132
+ 'totalSupply()',
133
+ 'tokenByIndex(uint256)' )
134
+
135
+ ...
136
+ ```
137
+
138
+
139
+ To be continued...
140
+
141
+
142
+
16
143
 
17
144
 
18
145
  ## License
data/Rakefile CHANGED
@@ -22,6 +22,7 @@ Hoe.spec 'abiparser' do
22
22
  ['cocos'],
23
23
  ['bytes'],
24
24
  ['digest-lite'],
25
+ ['abicoder'],
25
26
  ]
26
27
 
27
28
  self.licenses = ['Public Domain']
@@ -47,14 +47,20 @@ class Constructor
47
47
  end
48
48
 
49
49
 
50
- attr_reader :inputs
50
+ attr_reader :inputs, :input_types
51
51
 
52
52
  def initialize( inputs: [],
53
53
  payable: false )
54
54
  @inputs = inputs
55
55
  @payable = payable
56
+
57
+ ## parse inputs into types
58
+ ## note: use "calculated" sig(nature) and NOT the type
59
+ ## (differs for tuples, that is, types with components !!!)
60
+ @input_types = @inputs.map {|param| Type.parse( param.sig ) }
56
61
  end
57
62
 
63
+
58
64
  ## add - why? why not?
59
65
  ## def constant?() false; end
60
66
  ## alias_method :readonly?, :constant?
@@ -74,7 +80,7 @@ class Constructor
74
80
  buf << "(#{buf2.join(',')})"
75
81
  end
76
82
  buf
77
- end
83
+ end
78
84
 
79
85
 
80
86
  def doc
@@ -98,9 +104,7 @@ class Constructor
98
104
  end
99
105
  buf << ";"
100
106
  buf
101
- end
102
-
103
-
107
+ end
104
108
 
105
109
 
106
110
  end # class Constructor
@@ -63,8 +63,37 @@ class Contract
63
63
  @events = events
64
64
  @has_receive = has_receive
65
65
  @has_fallback = has_fallback
66
+
67
+ @selectors = {}
68
+
69
+ ## auto-add selectors (hashed signatures)
70
+ @funcs.each do |func|
71
+ sighash = func.sighash
72
+ puts "0x#{sighash} => #{func.sig}"
73
+
74
+ ## assert - no duplicates allowed
75
+ if @selectors[sighash]
76
+ puts "!! ERROR - duplicate function signature #{func.sig}; already in use; sorry"
77
+ exit 1
78
+ end
79
+
80
+ @selectors[sighash] = func
81
+ end
66
82
  end
67
83
 
84
+
85
+ ## return hexstrings of sig(natures) - why? why not?
86
+ ## rename to sighashes - why? why not?
87
+ def selectors() @selectors.keys; end
88
+
89
+
90
+ def support?( sig )
91
+ Utils.support?( @selectors.keys, sig )
92
+ end
93
+ alias_method :supports?, :support? ## add alternate spelling - why? why not?
94
+
95
+
96
+
68
97
  def constructor() @ctor; end
69
98
  def functions() @funcs; end
70
99
 
@@ -6,11 +6,14 @@ class Contract
6
6
  buf = ''
7
7
  buf << "interface #{name} {"
8
8
 
9
- if @ctor
10
- buf << "\n"
11
- buf << "// Constructor\n"
12
- buf << "#{@ctor.decl}\n"
13
- end
9
+
10
+ # include constructor - why? why not?
11
+ #
12
+ # if @ctor
13
+ # buf << "\n"
14
+ # buf << "// Constructor\n"
15
+ # buf << "#{@ctor.decl}\n"
16
+ # end
14
17
 
15
18
  if payable_functions.size > 0
16
19
  buf << "\n"
@@ -7,9 +7,9 @@ class Function
7
7
  inputs = o['inputs'].map {|param| Param.parse( param ) }
8
8
  outputs = o['outputs'].map {|param| Param.parse( param ) }
9
9
 
10
- payable = nil
11
- contant = nil
12
- pure = nil
10
+ payable = nil
11
+ constant = nil
12
+ pure = nil
13
13
 
14
14
  ## old soliditity before v0.6
15
15
  ## newer version uses stateMutability
@@ -54,10 +54,11 @@ class Function
54
54
 
55
55
 
56
56
  attr_reader :name,
57
- :inputs, :outputs
57
+ :inputs, :outputs,
58
+ :input_types, :output_types
58
59
 
59
60
  def initialize( name,
60
- inputs: [],
61
+ inputs: [],
61
62
  outputs: [],
62
63
  payable: false,
63
64
  constant: false,
@@ -65,10 +66,21 @@ class Function
65
66
  @name = name
66
67
  @inputs = inputs
67
68
  @outputs = outputs
68
-
69
69
  @payable = payable
70
70
  @constant = constant
71
71
  @pure = pure
72
+
73
+ ## parse inputs & outputs into types
74
+ ## note: use "calculated" sig(nature) and NOT the type
75
+ ## (differs for tuples, that is, types with components !!!)
76
+ @input_types = @inputs.map do |param|
77
+ Type.parse( param.sig )
78
+ end
79
+ @output_types = @outputs.map do |param|
80
+ ## pp param
81
+ ## puts "sig: #{param.sig}"
82
+ Type.parse( param.sig )
83
+ end
72
84
  end
73
85
 
74
86
 
@@ -92,11 +104,16 @@ class Function
92
104
  buf << "(#{buf2.join(',')})"
93
105
  end
94
106
  buf
95
- end
107
+ end
108
+
109
+ def sighash
110
+ keccak256( sig )[0,4].hexdigest
111
+ end
96
112
 
97
113
 
98
114
  def doc
99
- buf = "function #{@name}"
115
+ ## note: text with markdown formatting
116
+ buf = "function **#{@name}**"
100
117
  if @inputs.empty?
101
118
  buf << "()"
102
119
  else
@@ -134,7 +151,7 @@ class Function
134
151
  end
135
152
  buf << ";"
136
153
  buf
137
- end
154
+ end
138
155
 
139
156
 
140
157
  def types
@@ -0,0 +1,59 @@
1
+
2
+ module ABI
3
+
4
+
5
+ ## rename to QueryInterface or SupportInterface
6
+ ## or InterfaceType or InterfaceId or such - why? why not?
7
+ class Interface
8
+
9
+ attr_reader :interface_id
10
+
11
+
12
+ ##
13
+ ## todo/fix: make sure full function defs get passed in (not only sigs!!!)
14
+ def initialize( *functions )
15
+ @functions = functions
16
+ @selectors = {}
17
+
18
+ @functions.each do |func|
19
+ sig = func
20
+ sighash = keccak256( sig )[0,4].hexdigest
21
+ puts "0x#{sighash} => #{sig}"
22
+
23
+ ## assert - no duplicates allowed
24
+ if @selectors[sighash]
25
+ puts "!! ERROR - duplicate function signature #{sig}; already in use; sorry"
26
+ exit 1
27
+ end
28
+
29
+ @selectors[sighash] = sig
30
+ end
31
+ @interface_id = calc_interface_id
32
+ end
33
+
34
+
35
+ def calc_interface_id
36
+ interface_id = nil
37
+ @selectors.each do |sighash,_|
38
+ sighash = sighash.hex_to_bin ## note: convert to binary string (from hexstring)!!
39
+ interface_id = if interface_id.nil?
40
+ sighash ## init with sighash
41
+ else
42
+ interface_id ^ sighash ## use xor
43
+ end
44
+ end
45
+ interface_id.hexdigest
46
+ end
47
+
48
+
49
+ ## return hexstrings of sig(natures) - why? why not?
50
+ ## rename to sighashes - why? why not?
51
+ def selectors() @selectors.keys; end
52
+
53
+ def support?( sig )
54
+ Utils.support?( @selectors.keys, sig )
55
+ end
56
+ alias_method :supports?, :support? ## add alternate spelling - why? why not?
57
+
58
+ end ## class Interface
59
+ end # module ABI
@@ -1,36 +1,78 @@
1
1
  module ABI
2
2
  class Param
3
-
4
- attr_reader :type, :name
3
+ attr_reader :type, :name,
4
+ :internal_type,
5
+ :components
5
6
 
6
7
  def self.parse( o )
7
- type = o['type']
8
- name = o['name']
9
- new( type, name )
8
+ type = o['type']
9
+ internal_type = o['internalType']
10
+ name = o['name']
11
+ components = o['components'] ? o['components'].map { |c| parse( c ) } : nil
12
+
13
+ new( type, name,
14
+ internal_type: internal_type,
15
+ components: components )
10
16
  end
11
17
 
12
- def initialize( type, name ) ## note: type goes first!!!
13
- @type = type
14
- @name = name
18
+ ### check - find a "better" name for internal_type
19
+ ## use a keyword param - why? why not?
20
+ def initialize( type, name=nil,
21
+ internal_type: nil,
22
+ components: nil ) ## note: type goes first!!!
23
+ @type = type
24
+ ## note: convert empty string "" to nil - why? why not?
25
+ @name = if name && name.empty?
26
+ nil
27
+ else
28
+ name
29
+ end
30
+ @internal_type = if internal_type && internal_type.empty?
31
+ nil
32
+ else
33
+ internal_type
34
+ end
35
+ @components = components
15
36
  end
16
37
 
38
+
17
39
  def sig
18
- buf = "#{@type}"
19
- buf
40
+ @sig ||= begin
41
+ if @components
42
+ ## replace tuple with (type,...)
43
+ ## e.g. tuple[] becomes (type,...)[] etc.
44
+ tuple = @components.map {|c| c.sig }.join(',')
45
+ @type.sub( "tuple", "(#{tuple})" )
46
+ else
47
+ "#{@type}"
48
+ end
49
+ end
50
+ @sig
20
51
  end
21
52
 
53
+
22
54
  def doc
23
55
  buf = ''
24
- buf << "#{@type} "
25
- buf << (@name.empty? ? '_' : @name)
56
+ if @internal_type && @internal_type != sig
57
+ buf << "#{@internal_type} "
58
+ else
59
+ buf << "#{sig} "
60
+ end
61
+ buf << (@name ? @name : '_')
26
62
  buf
27
63
  end
28
64
 
29
65
  def decl
30
66
  buf = ''
31
- buf << "#{@type} "
32
- buf << (@name.empty? ? '_' : @name)
67
+ buf << "#{sig} "
68
+ buf << (@name ? @name : '_')
69
+ ## use inline comment - why? why not?
70
+ if @internal_type && @internal_type != sig
71
+ buf << " /* #{@internal_type} */"
72
+ end
33
73
  buf
34
74
  end
75
+
76
+
35
77
  end ## class Param
36
78
  end ## module ABI
@@ -0,0 +1,40 @@
1
+ module ABI
2
+ module Helpers
3
+
4
+
5
+ SIGHASH_RX = /\A
6
+ (0x)?
7
+ (?<sighash>[0-9a-f]{8})
8
+ \z/ix
9
+
10
+ def support?( selectors, sig )
11
+ if sig.is_a?( Interface )
12
+ iface = sig
13
+ iface.selectors.each do |sighash|
14
+ unless selectors.include?( sighash )
15
+ puts " sighash >#{sighash}< not found in interface"
16
+ return false
17
+ end
18
+ end
19
+ true
20
+ else
21
+ sighash = if m=SIGHASH_RX.match( sig )
22
+ m[:sighash].downcase ## assume it's sighash (hexstring)
23
+ else
24
+ ## for convenience allow (white)spaces; auto-strip - why? why not?
25
+ sig = sig.gsub( /[ \r\t\n]/, '' )
26
+ keccak256( sig )[0,4].hexdigest
27
+ end
28
+
29
+ selectors.include?( sighash ) ? true : false
30
+ end
31
+ end
32
+ end # module Helpers
33
+
34
+
35
+ module Utils
36
+ extend Helpers
37
+ ## e.g. Utils.supports?( selectors, sig ) etc.
38
+ end
39
+
40
+ end # module ABI
@@ -1,8 +1,7 @@
1
1
 
2
2
  module ABIParser
3
-
4
3
  MAJOR = 0
5
- MINOR = 0
4
+ MINOR = 1
6
5
  PATCH = 1
7
6
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
7
 
data/lib/abiparser.rb CHANGED
@@ -6,9 +6,27 @@ require 'digest-lite'
6
6
  ## extend String
7
7
  class String
8
8
  alias_method :hexdigest, :bin_to_hex ## note: bin_to_hex added via Bytes!!!
9
+
10
+ # given two numeric strings,
11
+ # returns the bitwise xor string
12
+ def xor(other)
13
+ a = self.bytes
14
+ b = other.bytes
15
+ ## todo/check: cut-off on lower count (lc) - why? why not?
16
+ lc = (a.size < b.size) ? a.size : b.size
17
+ c = []
18
+ lc.times do |i|
19
+ c << (a[i] ^ b[i])
20
+ end
21
+ c = c.pack( 'C*' )
22
+ puts "#{self.bin_to_hex} ^ #{other.bin_to_hex} = #{c.bin_to_hex}<"
23
+ c
24
+ end
25
+ alias_method :^, :xor
9
26
  end # class String
10
27
 
11
28
 
29
+
12
30
  def keccak256( bin )
13
31
  Digest::KeccakLite.new( 256 ).digest( bin )
14
32
  end
@@ -18,15 +36,84 @@ def sig( bin )
18
36
  end
19
37
 
20
38
 
39
+ require 'abicoder'
40
+
21
41
 
22
42
  ## our own code
23
43
  require_relative 'abiparser/version' # note: let version always go first
44
+
24
45
  require_relative 'abiparser/param'
25
46
  require_relative 'abiparser/constructor'
26
47
  require_relative 'abiparser/function'
48
+ require_relative 'abiparser/utils'
27
49
  require_relative 'abiparser/contract'
50
+ require_relative 'abiparser/interface'
51
+
52
+ require_relative 'abiparser/export/interface'
53
+
54
+
55
+
56
+
57
+ ## note: make "global" constants - why? why not?
58
+
59
+ ## IERC165 0x01ffc9a7
60
+ IERC165 = ABI::Interface.new(
61
+ 'supportsInterface(bytes4)',
62
+ )
63
+
64
+ ## IERC20 0x36372b07
65
+ IERC20 = ABI::Interface.new(
66
+ 'totalSupply()',
67
+ 'balanceOf(address)',
68
+ 'allowance(address,address)',
69
+ 'transfer(address,uint256)',
70
+ 'approve(address,uint256)',
71
+ 'transferFrom(address,address,uint256)'
72
+ )
73
+
74
+ ## IERC20_NAME 0x06fdde03
75
+ IERC20_NAME = ABI::Interface.new(
76
+ 'name()'
77
+ )
78
+
79
+ ## IERC20_SYMBOL 0x95d89b41
80
+ IERC20_SYMBOL = ABI::Interface.new(
81
+ 'symbol()'
82
+ )
83
+
84
+ ## IERC20_DECIMALS 0x313ce567
85
+ IERC20_DECIMALS = ABI::Interface.new(
86
+ 'decimals()'
87
+ )
88
+
89
+ ## IERC721 0x80ac58cd
90
+ IERC721 = ABI::Interface.new(
91
+ 'balanceOf(address)',
92
+ 'ownerOf(uint256)',
93
+ 'approve(address,uint256)',
94
+ 'getApproved(uint256)',
95
+ 'setApprovalForAll(address,bool)',
96
+ 'isApprovedForAll(address,address)',
97
+ 'transferFrom(address,address,uint256)',
98
+ 'safeTransferFrom(address,address,uint256)',
99
+ 'safeTransferFrom(address,address,uint256,bytes)'
100
+ )
101
+
102
+ ## IERC721_METADATA 0x5b5e139f
103
+ IERC721_METADATA = ABI::Interface.new(
104
+ 'name()',
105
+ 'symbol()',
106
+ 'tokenURI(uint256)'
107
+ )
108
+
109
+ ## IERC721_ENUMERABLE 0x780e9d63
110
+ IERC721_ENUMERABLE = ABI::Interface.new(
111
+ 'tokenOfOwnerByIndex(address,uint256)',
112
+ 'totalSupply()',
113
+ 'tokenByIndex(uint256)'
114
+ )
115
+
28
116
 
29
- require_relative 'abiparser/export/interface.rb'
30
117
 
31
118
 
32
119
 
@@ -37,9 +124,6 @@ module ABI
37
124
  end # module ABI
38
125
 
39
126
 
40
- ## add convenience alternate spellings - why? why not?
41
- Abi = ABI
42
-
43
127
 
44
- puts AbiParser.banner
128
+ puts ABIParser.banner
45
129
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abiparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-26 00:00:00.000000000 Z
11
+ date: 2023-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cocos
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: abicoder
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rdoc
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -105,7 +119,9 @@ files:
105
119
  - lib/abiparser/contract.rb
106
120
  - lib/abiparser/export/interface.rb
107
121
  - lib/abiparser/function.rb
122
+ - lib/abiparser/interface.rb
108
123
  - lib/abiparser/param.rb
124
+ - lib/abiparser/utils.rb
109
125
  - lib/abiparser/version.rb
110
126
  homepage: https://github.com/rubycocos/blockchain
111
127
  licenses: