abiparser 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Manifest.txt +2 -0
- data/README.md +127 -0
- data/lib/abiparser/constructor.rb +2 -4
- data/lib/abiparser/contract.rb +29 -0
- data/lib/abiparser/export/interface.rb +8 -5
- data/lib/abiparser/function.rb +11 -6
- data/lib/abiparser/interface.rb +59 -0
- data/lib/abiparser/param.rb +37 -11
- data/lib/abiparser/utils.rb +40 -0
- data/lib/abiparser/version.rb +2 -3
- data/lib/abiparser.rb +84 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43f7d1f45a66ea6fd2deb690979c26f4289a666692bcb84c81420dbab5c2ab8b
|
4
|
+
data.tar.gz: 487f1407542dc6d6f5e22b2975f4a7828fc0f08f5147961dc44230486bccbe71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fc14d110513a91161272beb5a9e8d41401fe8ba5407d52beb43b782ac2b173108aaea79738b4f75d00439bf17908257376100c1d4166dc34434f936019eddbf
|
7
|
+
data.tar.gz: ed21d7bcdbb58144832ba46c82d6fae1c1ec22f501936b34902e68c56ab44a556f219c35294cf09a836382252d77e67de231476b027724fcb60e681d3925d90f
|
data/Manifest.txt
CHANGED
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/lib/abiparser/contract.rb
CHANGED
@@ -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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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"
|
data/lib/abiparser/function.rb
CHANGED
@@ -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
|
11
|
-
|
12
|
-
pure
|
10
|
+
payable = nil
|
11
|
+
constant = nil
|
12
|
+
pure = nil
|
13
13
|
|
14
14
|
## old soliditity before v0.6
|
15
15
|
## newer version uses stateMutability
|
@@ -92,11 +92,16 @@ class Function
|
|
92
92
|
buf << "(#{buf2.join(',')})"
|
93
93
|
end
|
94
94
|
buf
|
95
|
-
|
95
|
+
end
|
96
|
+
|
97
|
+
def sighash
|
98
|
+
keccak256( sig )[0,4].hexdigest
|
99
|
+
end
|
96
100
|
|
97
101
|
|
98
102
|
def doc
|
99
|
-
|
103
|
+
## note: text with markdown formatting
|
104
|
+
buf = "function **#{@name}**"
|
100
105
|
if @inputs.empty?
|
101
106
|
buf << "()"
|
102
107
|
else
|
@@ -134,7 +139,7 @@ class Function
|
|
134
139
|
end
|
135
140
|
buf << ";"
|
136
141
|
buf
|
137
|
-
end
|
142
|
+
end
|
138
143
|
|
139
144
|
|
140
145
|
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
|
data/lib/abiparser/param.rb
CHANGED
@@ -1,19 +1,35 @@
|
|
1
1
|
module ABI
|
2
2
|
class Param
|
3
|
-
|
4
|
-
attr_reader :type, :name
|
3
|
+
attr_reader :type, :name, :internal_type
|
5
4
|
|
6
5
|
def self.parse( o )
|
7
|
-
type
|
8
|
-
|
9
|
-
|
6
|
+
type = o['type']
|
7
|
+
internal_type = o['internalType']
|
8
|
+
name = o['name']
|
9
|
+
|
10
|
+
new( type, name,
|
11
|
+
internal_type: internal_type )
|
10
12
|
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
### check - find a "better" name for internal_type
|
15
|
+
## use a keyword param - why? why not?
|
16
|
+
def initialize( type, name=nil,
|
17
|
+
internal_type: nil ) ## note: type goes first!!!
|
18
|
+
@type = type
|
19
|
+
## note: convert empty string "" to nil - why? why not?
|
20
|
+
@name = if name && name.empty?
|
21
|
+
nil
|
22
|
+
else
|
23
|
+
name
|
24
|
+
end
|
25
|
+
@internal_type = if internal_type && internal_type.empty?
|
26
|
+
nil
|
27
|
+
else
|
28
|
+
internal_type
|
29
|
+
end
|
15
30
|
end
|
16
31
|
|
32
|
+
|
17
33
|
def sig
|
18
34
|
buf = "#{@type}"
|
19
35
|
buf
|
@@ -21,16 +37,26 @@ class Param
|
|
21
37
|
|
22
38
|
def doc
|
23
39
|
buf = ''
|
24
|
-
|
25
|
-
|
40
|
+
if @internal_type && @internal_type != @type
|
41
|
+
buf << "#{@internal_type} "
|
42
|
+
else
|
43
|
+
buf << "#{@type} "
|
44
|
+
end
|
45
|
+
buf << (@name ? @name : '_')
|
26
46
|
buf
|
27
47
|
end
|
28
48
|
|
29
49
|
def decl
|
30
50
|
buf = ''
|
31
51
|
buf << "#{@type} "
|
32
|
-
buf << (@name
|
52
|
+
buf << (@name ? @name : '_')
|
53
|
+
## use inline comment - why? why not?
|
54
|
+
if @internal_type && @internal_type != @type
|
55
|
+
buf << " /* #{@internal_type} */"
|
56
|
+
end
|
33
57
|
buf
|
34
58
|
end
|
59
|
+
|
60
|
+
|
35
61
|
end ## class Param
|
36
62
|
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
|
data/lib/abiparser/version.rb
CHANGED
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
|
@@ -24,12 +42,78 @@ require_relative 'abiparser/version' # note: let version always go first
|
|
24
42
|
require_relative 'abiparser/param'
|
25
43
|
require_relative 'abiparser/constructor'
|
26
44
|
require_relative 'abiparser/function'
|
45
|
+
require_relative 'abiparser/utils'
|
27
46
|
require_relative 'abiparser/contract'
|
47
|
+
require_relative 'abiparser/interface'
|
28
48
|
|
29
49
|
require_relative 'abiparser/export/interface.rb'
|
30
50
|
|
31
51
|
|
32
52
|
|
53
|
+
|
54
|
+
## note: make "global" constants - why? why not?
|
55
|
+
|
56
|
+
## IERC165 0x01ffc9a7
|
57
|
+
IERC165 = ABI::Interface.new(
|
58
|
+
'supportsInterface(bytes4)',
|
59
|
+
)
|
60
|
+
|
61
|
+
## IERC20 0x36372b07
|
62
|
+
IERC20 = ABI::Interface.new(
|
63
|
+
'totalSupply()',
|
64
|
+
'balanceOf(address)',
|
65
|
+
'allowance(address,address)',
|
66
|
+
'transfer(address,uint256)',
|
67
|
+
'approve(address,uint256)',
|
68
|
+
'transferFrom(address,address,uint256)'
|
69
|
+
)
|
70
|
+
|
71
|
+
## IERC20_NAME 0x06fdde03
|
72
|
+
IERC20_NAME = ABI::Interface.new(
|
73
|
+
'name()'
|
74
|
+
)
|
75
|
+
|
76
|
+
## IERC20_SYMBOL 0x95d89b41
|
77
|
+
IERC20_SYMBOL = ABI::Interface.new(
|
78
|
+
'symbol()'
|
79
|
+
)
|
80
|
+
|
81
|
+
## IERC20_DECIMALS 0x313ce567
|
82
|
+
IERC20_DECIMALS = ABI::Interface.new(
|
83
|
+
'decimals()'
|
84
|
+
)
|
85
|
+
|
86
|
+
## IERC721 0x80ac58cd
|
87
|
+
IERC721 = ABI::Interface.new(
|
88
|
+
'balanceOf(address)',
|
89
|
+
'ownerOf(uint256)',
|
90
|
+
'approve(address,uint256)',
|
91
|
+
'getApproved(uint256)',
|
92
|
+
'setApprovalForAll(address,bool)',
|
93
|
+
'isApprovedForAll(address,address)',
|
94
|
+
'transferFrom(address,address,uint256)',
|
95
|
+
'safeTransferFrom(address,address,uint256)',
|
96
|
+
'safeTransferFrom(address,address,uint256,bytes)'
|
97
|
+
)
|
98
|
+
|
99
|
+
## IERC721_METADATA 0x5b5e139f
|
100
|
+
IERC721_METADATA = ABI::Interface.new(
|
101
|
+
'name()',
|
102
|
+
'symbol()',
|
103
|
+
'tokenURI(uint256)'
|
104
|
+
)
|
105
|
+
|
106
|
+
## IERC721_ENUMERABLE 0x780e9d63
|
107
|
+
IERC721_ENUMERABLE = ABI::Interface.new(
|
108
|
+
'tokenOfOwnerByIndex(address,uint256)',
|
109
|
+
'totalSupply()',
|
110
|
+
'tokenByIndex(uint256)'
|
111
|
+
)
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
|
33
117
|
module ABI
|
34
118
|
def self.read( path ) Contract.read( path ); end
|
35
119
|
|
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
|
4
|
+
version: 0.1.0
|
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-
|
11
|
+
date: 2022-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cocos
|
@@ -105,7 +105,9 @@ files:
|
|
105
105
|
- lib/abiparser/contract.rb
|
106
106
|
- lib/abiparser/export/interface.rb
|
107
107
|
- lib/abiparser/function.rb
|
108
|
+
- lib/abiparser/interface.rb
|
108
109
|
- lib/abiparser/param.rb
|
110
|
+
- lib/abiparser/utils.rb
|
109
111
|
- lib/abiparser/version.rb
|
110
112
|
homepage: https://github.com/rubycocos/blockchain
|
111
113
|
licenses:
|