abiparser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 77899a7da00b8be7b61c97d2f1ebad297a6d33f74bd081c59b17f8b66bca78f1
4
+ data.tar.gz: 15a102dc8505eb359fcb5d117de026e9308641e714ea50096895ee15fb4d655e
5
+ SHA512:
6
+ metadata.gz: 2bf5a3d5928df6f9d5a650f50ca05df22edb82f0d305a5ef66c552b36fee9b33d6166b63dfd4e878c8a32f7a86e042517159cc6b0155cf96734b36a0ab596817
7
+ data.tar.gz: 8181ddd11ad89481204f1796ef4eebc854d10ec83fb8cd6d3fd45ce8da830cff2fd1273c726c507853843442c174c603bd66fcb735ae4aabf433141827befebb
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2022-12-26
2
+
3
+ * Everything is new. First release
data/Manifest.txt ADDED
@@ -0,0 +1,11 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/abiparser.rb
6
+ lib/abiparser/constructor.rb
7
+ lib/abiparser/contract.rb
8
+ lib/abiparser/export/interface.rb
9
+ lib/abiparser/function.rb
10
+ lib/abiparser/param.rb
11
+ lib/abiparser/version.rb
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Application Binary Inteface (ABI) Parser For Ethereum & Co.
2
+
3
+ abiparser - application binary interface (abi) parser machinery / helper for Ethereum & Co. (blockchain) contracts
4
+
5
+
6
+ * home :: [github.com/rubycocos/blockchain](https://github.com/rubycocos/blockchain)
7
+ * bugs :: [github.com/rubycocos/blockchain/issues](https://github.com/rubycocos/blockchain/issues)
8
+ * gem :: [rubygems.org/gems/abiparser](https://rubygems.org/gems/abiparser)
9
+ * rdoc :: [rubydoc.info/gems/abiparser](http://rubydoc.info/gems/abiparser)
10
+
11
+
12
+
13
+ ## Usage
14
+
15
+
16
+
17
+
18
+ ## License
19
+
20
+ The scripts are dedicated to the public domain.
21
+ Use it as you please with no restrictions whatsoever.
22
+
23
+
24
+ ## Questions? Comments?
25
+
26
+
27
+ Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.
28
+
29
+
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ require 'hoe'
2
+ require './lib/abiparser/version.rb'
3
+
4
+
5
+ Hoe.spec 'abiparser' do
6
+
7
+ self.version = ABIParser::VERSION
8
+
9
+ self.summary = "abiparser - application binary interface (abi) parser machinery / helper for Ethereum & Co. (blockchain) contracts"
10
+ self.description = summary
11
+
12
+ self.urls = { home: 'https://github.com/rubycocos/blockchain' }
13
+
14
+ self.author = 'Gerald Bauer'
15
+ self.email = 'wwwmake@googlegroups.com'
16
+
17
+ # switch extension to .markdown for gihub formatting
18
+ self.readme_file = 'README.md'
19
+ self.history_file = 'CHANGELOG.md'
20
+
21
+ self.extra_deps = [
22
+ ['cocos'],
23
+ ['bytes'],
24
+ ['digest-lite'],
25
+ ]
26
+
27
+ self.licenses = ['Public Domain']
28
+
29
+ self.spec_extras = {
30
+ required_ruby_version: '>= 2.3'
31
+ }
32
+
33
+ end
34
+
@@ -0,0 +1,109 @@
1
+ module ABI
2
+ class Constructor
3
+
4
+ def self.parse( o )
5
+ ## note:
6
+ ## - has no name
7
+ ## - has no ouptputs
8
+ ## e.g.
9
+ ## {"inputs":[],
10
+ ## "stateMutability":"nonpayable",
11
+ ## "type":"constructor"}
12
+
13
+ inputs = o['inputs'].map {|param| Param.parse( param ) }
14
+ payable = nil
15
+
16
+ ## old soliditity before v0.6
17
+ ## newer version uses stateMutability
18
+ if o.has_key?( 'stateMutability' )
19
+ case o[ 'stateMutability' ]
20
+ when 'nonpayable' ## default
21
+ payable = false
22
+ when 'payable'
23
+ payable = true
24
+ else
25
+ pp o
26
+ ## todo/fix: change to ParseError
27
+ raise ArgumentError, "unexpected stateMutability (constructor) value ; got: #{ o[ 'stateMutability' ]}"
28
+ end
29
+ end
30
+
31
+ ## check - assert "strict" abi version keys - why? why not?
32
+ if o.has_key?( 'stateMutability' ) && (o.has_key?( 'payable') || o.has_key?( 'constant'))
33
+ pp o
34
+ puts "!! WARN: ABI version mismatch? got stateMutability AND payable OR constant"
35
+ exit 1
36
+ end
37
+
38
+ if o.has_key?( 'constant')
39
+ pp o
40
+ puts "!! WARN: constant for constructor possible?"
41
+ exit 1
42
+ end
43
+
44
+ payable = o['payable'] if o.has_key?( 'payable')
45
+
46
+ new( inputs: inputs, payable: payable )
47
+ end
48
+
49
+
50
+ attr_reader :inputs
51
+
52
+ def initialize( inputs: [],
53
+ payable: false )
54
+ @inputs = inputs
55
+ @payable = payable
56
+ end
57
+
58
+ ## add - why? why not?
59
+ ## def constant?() false; end
60
+ ## alias_method :readonly?, :constant?
61
+
62
+ def payable?() @payable; end
63
+
64
+ def sig
65
+ ## note: signature
66
+ ## only includes name and inputs
67
+ ## excludes / drops outputs!!!
68
+
69
+ buf = "constructor"
70
+ if @inputs.empty?
71
+ buf << "()"
72
+ else
73
+ buf2 = @inputs.map {|param| param.sig }
74
+ buf << "(#{buf2.join(',')})"
75
+ end
76
+ buf
77
+ end
78
+
79
+
80
+ def doc
81
+ buf = "constructor"
82
+ if @inputs.empty?
83
+ buf << "()"
84
+ else
85
+ buf2 = @inputs.map {|param| param.doc }
86
+ buf << "(#{buf2.join(', ')})"
87
+ end
88
+ buf
89
+ end
90
+
91
+ def decl
92
+ buf = "constructor"
93
+ if @inputs.empty?
94
+ buf << "()"
95
+ else
96
+ buf2 = @inputs.map {|param| param.decl }
97
+ buf << "(#{buf2.join(', ')})"
98
+ end
99
+ buf << ";"
100
+ buf
101
+ end
102
+
103
+
104
+
105
+
106
+ end # class Constructor
107
+ end # module ABI
108
+
109
+
@@ -0,0 +1,91 @@
1
+ module ABI
2
+ class Contract
3
+
4
+ def self.read( path )
5
+ data = read_json( path )
6
+ ## pp data
7
+ parse( data )
8
+ end
9
+
10
+ def self.parse( data )
11
+ ## note: auto-convert (parse) from json if string passed-in
12
+ data = JSON.parse( data ) if data.is_a?( String )
13
+
14
+ ctor = nil
15
+ funcs = []
16
+ has_fallback = false
17
+ has_receive = true
18
+
19
+ data.each do |o|
20
+ if o['type'] == 'function'
21
+ funcs << Function.parse( o )
22
+ elsif o['type'] == 'constructor'
23
+ raise ArgumentError, "constructor already defined; only one declaration allowed" if ctor
24
+ ctor = Constructor.parse( o )
25
+ elsif o['type'] == 'event'
26
+ elsif o['type'] == 'receive'
27
+ ## skip for now
28
+ ## e.g.
29
+ ## {"stateMutability": "payable",
30
+ ## "type": "receive"}
31
+ elsif o['type'] == 'fallback'
32
+ ## skip for now
33
+ ## e.g.
34
+ ## {"stateMutability"=>"nonpayable",
35
+ ## "type"=>"fallback"}
36
+ elsif o['type'] == 'error'
37
+ ## skip for now
38
+ ## e.g.
39
+ ## {"inputs":[],
40
+ ## "name":"ApprovalCallerNotOwnerNorApproved",
41
+ ## "type":"error"}
42
+ else
43
+ pp o
44
+ raise TypeError, "expected function or event; sorry: got #{o['type']}"
45
+ end
46
+ end
47
+ new( constructor: ctor,
48
+ functions: funcs,
49
+ events: [],
50
+ has_receive: has_receive,
51
+ has_fallback: has_fallback )
52
+ end
53
+
54
+
55
+
56
+ def initialize( constructor: nil,
57
+ functions: [],
58
+ events: [],
59
+ has_receive: false,
60
+ has_fallback: false )
61
+ @ctor = constructor
62
+ @funcs = functions
63
+ @events = events
64
+ @has_receive = has_receive
65
+ @has_fallback = has_fallback
66
+ end
67
+
68
+ def constructor() @ctor; end
69
+ def functions() @funcs; end
70
+
71
+ ###
72
+ ## how to name functions categories ???
73
+ ## - use pay, writer, reader, helper - why? why not?
74
+ def payable_functions
75
+ @funcs.select { |func| func.payable? }
76
+ end
77
+
78
+ def transact_functions ## add write funcs alias - why? why not?
79
+ @funcs.select { |func| !func.payable? && !func.constant? }
80
+ end
81
+
82
+ def query_functions ## add read funcs alias - why? why not?
83
+ @funcs.select { |func| !func.payable? && !func.pure? && func.constant? }
84
+ end
85
+
86
+ def helper_functions ## add pure ?? funcs alias - why? why not?
87
+ @funcs.select { |func| func.pure? }
88
+ end
89
+
90
+ end # class Contract
91
+ end # module ABI
@@ -0,0 +1,53 @@
1
+ module ABI
2
+ class Contract
3
+
4
+
5
+ def generate_interface( name: ) ## interface declarations
6
+ buf = ''
7
+ buf << "interface #{name} {"
8
+
9
+ if @ctor
10
+ buf << "\n"
11
+ buf << "// Constructor\n"
12
+ buf << "#{@ctor.decl}\n"
13
+ end
14
+
15
+ if payable_functions.size > 0
16
+ buf << "\n"
17
+ buf << "// #{payable_functions.size} Payable Function(s)\n"
18
+ payable_functions.each do |func|
19
+ buf << "#{func.decl}\n"
20
+ end
21
+ end
22
+
23
+ if transact_functions.size > 0
24
+ buf << "\n"
25
+ buf << "// #{transact_functions.size} Transact Functions(s)\n"
26
+ transact_functions.each do |func|
27
+ buf << "#{func.decl}\n"
28
+ end
29
+ end
30
+
31
+ if query_functions.size > 0
32
+ buf << "\n"
33
+ buf << "// #{query_functions.size} Query Functions(s)\n"
34
+ query_functions.each do |func|
35
+ buf << "#{func.decl}\n"
36
+ end
37
+ end
38
+
39
+ if helper_functions.size > 0
40
+ buf << "\n"
41
+ buf << "// #{helper_functions.size} Helper Functions(s)\n\n"
42
+ helper_functions.each do |func|
43
+ buf << "#{func.decl}\n"
44
+ end
45
+ end
46
+
47
+ buf << "}\n"
48
+ buf
49
+ end
50
+
51
+
52
+ end ## class Contract
53
+ end ## module ABI
@@ -0,0 +1,148 @@
1
+ module ABI
2
+ class Function
3
+
4
+ def self.parse( o )
5
+ ## todo/fix: assert type function (or contructor) ??
6
+ name = o['name']
7
+ inputs = o['inputs'].map {|param| Param.parse( param ) }
8
+ outputs = o['outputs'].map {|param| Param.parse( param ) }
9
+
10
+ payable = nil
11
+ contant = nil
12
+ pure = nil
13
+
14
+ ## old soliditity before v0.6
15
+ ## newer version uses stateMutability
16
+ if o.has_key?( 'stateMutability' )
17
+ case o[ 'stateMutability' ]
18
+ when 'nonpayable' ## default
19
+ payable = false
20
+ constant = false
21
+ when 'payable'
22
+ payable = true
23
+ constant = false
24
+ when 'view'
25
+ payable = false
26
+ constant = true
27
+ when 'pure'
28
+ payable = false
29
+ constant = true
30
+ pure = true
31
+ else
32
+ pp o
33
+ ## todo/fix: change to ParseError
34
+ raise ArgumentError, "unexpected stateMutability value; got: #{ o[ 'stateMutability' ]}"
35
+ end
36
+ end
37
+
38
+ ## check - assert "strict" abi version keys - why? why not?
39
+ if o.has_key?( 'stateMutability' ) && (o.has_key?( 'payable') || o.has_key?( 'constant'))
40
+ pp o
41
+ puts "!! WARN: ABI version mismatch? got stateMutability AND payable OR constant"
42
+ exit 1
43
+ end
44
+
45
+ payable = o['payable'] if o.has_key?( 'payable')
46
+ constant = o['constant'] if o.has_key?( 'constant')
47
+
48
+
49
+ new( name, inputs: inputs, outputs: outputs,
50
+ payable: payable,
51
+ constant: constant,
52
+ pure: pure )
53
+ end
54
+
55
+
56
+ attr_reader :name,
57
+ :inputs, :outputs
58
+
59
+ def initialize( name,
60
+ inputs: [],
61
+ outputs: [],
62
+ payable: false,
63
+ constant: false,
64
+ pure: false )
65
+ @name = name
66
+ @inputs = inputs
67
+ @outputs = outputs
68
+
69
+ @payable = payable
70
+ @constant = constant
71
+ @pure = pure
72
+ end
73
+
74
+
75
+ def constant?() @constant; end
76
+ alias_method :readonly?, :constant?
77
+
78
+ def payable?() @payable; end
79
+ def pure?() @pure; end
80
+
81
+
82
+ def sig
83
+ ## note: signature
84
+ ## only includes name and inputs
85
+ ## excludes / drops outputs!!!
86
+
87
+ buf = "#{@name}"
88
+ if @inputs.empty?
89
+ buf << "()"
90
+ else
91
+ buf2 = @inputs.map {|param| param.sig }
92
+ buf << "(#{buf2.join(',')})"
93
+ end
94
+ buf
95
+ end
96
+
97
+
98
+ def doc
99
+ buf = "function #{@name}"
100
+ if @inputs.empty?
101
+ buf << "()"
102
+ else
103
+ buf2 = @inputs.map {|param| param.doc }
104
+ buf << "(#{buf2.join(', ')})"
105
+ end
106
+ if @outputs.empty?
107
+ ## do nothing
108
+ else
109
+ buf << " ⇒ "
110
+ buf2 = @outputs.map {|param| param.doc }
111
+ buf << "(#{buf2.join(', ')})"
112
+ end
113
+ buf
114
+ end
115
+
116
+ def decl
117
+ buf = "function #{@name}"
118
+ if @inputs.empty?
119
+ buf << "()"
120
+ else
121
+ buf2 = @inputs.map {|param| param.decl }
122
+ buf << "(#{buf2.join(', ')})"
123
+ end
124
+ buf << " payable " if @payable
125
+ buf << " view " if @constant && !@pure
126
+ buf << " pure " if @constant && @pure
127
+
128
+ if @outputs.empty?
129
+ ## do nothing
130
+ else
131
+ buf << " returns "
132
+ buf2 = @outputs.map {|param| param.decl }
133
+ buf << "(#{buf2.join(', ')})"
134
+ end
135
+ buf << ";"
136
+ buf
137
+ end
138
+
139
+
140
+ def types
141
+ ## for debugging / analytics return all used types (input+output)
142
+ @inputs.map {|param| param.type } +
143
+ @outputs.map {|param| param.type }
144
+ end
145
+
146
+ end ## class Function
147
+ end ## module ABI
148
+
@@ -0,0 +1,36 @@
1
+ module ABI
2
+ class Param
3
+
4
+ attr_reader :type, :name
5
+
6
+ def self.parse( o )
7
+ type = o['type']
8
+ name = o['name']
9
+ new( type, name )
10
+ end
11
+
12
+ def initialize( type, name ) ## note: type goes first!!!
13
+ @type = type
14
+ @name = name
15
+ end
16
+
17
+ def sig
18
+ buf = "#{@type}"
19
+ buf
20
+ end
21
+
22
+ def doc
23
+ buf = ''
24
+ buf << "#{@type} "
25
+ buf << (@name.empty? ? '_' : @name)
26
+ buf
27
+ end
28
+
29
+ def decl
30
+ buf = ''
31
+ buf << "#{@type} "
32
+ buf << (@name.empty? ? '_' : @name)
33
+ buf
34
+ end
35
+ end ## class Param
36
+ end ## module ABI
@@ -0,0 +1,25 @@
1
+
2
+ module ABIParser
3
+
4
+ MAJOR = 0
5
+ MINOR = 0
6
+ PATCH = 1
7
+ VERSION = [MAJOR,MINOR,PATCH].join('.')
8
+
9
+ def self.version
10
+ VERSION
11
+ end
12
+
13
+ def self.banner
14
+ "abiparser/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
15
+ end
16
+
17
+ def self.root
18
+ File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
19
+ end
20
+
21
+ end # module ABIParser
22
+
23
+ ## add convenience alternate spellings - why? why not?
24
+ AbiParser = ABIParser
25
+
data/lib/abiparser.rb ADDED
@@ -0,0 +1,45 @@
1
+ require 'cocos'
2
+ require 'bytes'
3
+ require 'digest-lite'
4
+
5
+
6
+ ## extend String
7
+ class String
8
+ alias_method :hexdigest, :bin_to_hex ## note: bin_to_hex added via Bytes!!!
9
+ end # class String
10
+
11
+
12
+ def keccak256( bin )
13
+ Digest::KeccakLite.new( 256 ).digest( bin )
14
+ end
15
+
16
+ def sig( bin )
17
+ keccak256( bin )[0,4]
18
+ end
19
+
20
+
21
+
22
+ ## our own code
23
+ require_relative 'abiparser/version' # note: let version always go first
24
+ require_relative 'abiparser/param'
25
+ require_relative 'abiparser/constructor'
26
+ require_relative 'abiparser/function'
27
+ require_relative 'abiparser/contract'
28
+
29
+ require_relative 'abiparser/export/interface.rb'
30
+
31
+
32
+
33
+ module ABI
34
+ def self.read( path ) Contract.read( path ); end
35
+
36
+ def self.parse( data ) Contract.parse( data ); end
37
+ end # module ABI
38
+
39
+
40
+ ## add convenience alternate spellings - why? why not?
41
+ Abi = ABI
42
+
43
+
44
+ puts AbiParser.banner
45
+
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: abiparser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gerald Bauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-12-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cocos
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bytes
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: digest-lite
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
62
+ - - "<"
63
+ - !ruby/object:Gem::Version
64
+ version: '7'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '4.0'
72
+ - - "<"
73
+ - !ruby/object:Gem::Version
74
+ version: '7'
75
+ - !ruby/object:Gem::Dependency
76
+ name: hoe
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.23'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.23'
89
+ description: abiparser - application binary interface (abi) parser machinery / helper
90
+ for Ethereum & Co. (blockchain) contracts
91
+ email: wwwmake@googlegroups.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files:
95
+ - CHANGELOG.md
96
+ - Manifest.txt
97
+ - README.md
98
+ files:
99
+ - CHANGELOG.md
100
+ - Manifest.txt
101
+ - README.md
102
+ - Rakefile
103
+ - lib/abiparser.rb
104
+ - lib/abiparser/constructor.rb
105
+ - lib/abiparser/contract.rb
106
+ - lib/abiparser/export/interface.rb
107
+ - lib/abiparser/function.rb
108
+ - lib/abiparser/param.rb
109
+ - lib/abiparser/version.rb
110
+ homepage: https://github.com/rubycocos/blockchain
111
+ licenses:
112
+ - Public Domain
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options:
116
+ - "--main"
117
+ - README.md
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '2.3'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubygems_version: 3.3.7
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: abiparser - application binary interface (abi) parser machinery / helper
135
+ for Ethereum & Co. (blockchain) contracts
136
+ test_files: []