etherlite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +49 -0
  6. data/Gemfile +4 -0
  7. data/Guardfile +10 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +41 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/etherlite.gemspec +31 -0
  14. data/lib/etherlite.rb +66 -0
  15. data/lib/etherlite/abi.rb +22 -0
  16. data/lib/etherlite/account.rb +67 -0
  17. data/lib/etherlite/address.rb +21 -0
  18. data/lib/etherlite/api/address.rb +21 -0
  19. data/lib/etherlite/api/node.rb +36 -0
  20. data/lib/etherlite/client.rb +11 -0
  21. data/lib/etherlite/commands/abi/load_contract.rb +66 -0
  22. data/lib/etherlite/commands/abi/load_function.rb +28 -0
  23. data/lib/etherlite/commands/abi/load_type.rb +55 -0
  24. data/lib/etherlite/commands/base.rb +0 -0
  25. data/lib/etherlite/commands/contract/event_base/decode_log_inputs.rb +21 -0
  26. data/lib/etherlite/commands/contract/function/encode_arguments.rb +32 -0
  27. data/lib/etherlite/commands/utils/validate_address.rb +25 -0
  28. data/lib/etherlite/configuration.rb +33 -0
  29. data/lib/etherlite/connection.rb +39 -0
  30. data/lib/etherlite/contract/base.rb +58 -0
  31. data/lib/etherlite/contract/event_base.rb +36 -0
  32. data/lib/etherlite/contract/event_input.rb +19 -0
  33. data/lib/etherlite/contract/function.rb +43 -0
  34. data/lib/etherlite/railtie.rb +29 -0
  35. data/lib/etherlite/railties/configuration_extensions.rb +9 -0
  36. data/lib/etherlite/railties/utils.rb +13 -0
  37. data/lib/etherlite/types/address.rb +20 -0
  38. data/lib/etherlite/types/array_base.rb +36 -0
  39. data/lib/etherlite/types/array_dynamic.rb +13 -0
  40. data/lib/etherlite/types/array_fixed.rb +23 -0
  41. data/lib/etherlite/types/base.rb +27 -0
  42. data/lib/etherlite/types/bool.rb +26 -0
  43. data/lib/etherlite/types/byte_string.rb +17 -0
  44. data/lib/etherlite/types/bytes.rb +19 -0
  45. data/lib/etherlite/types/fixed.rb +38 -0
  46. data/lib/etherlite/types/integer.rb +38 -0
  47. data/lib/etherlite/types/string.rb +10 -0
  48. data/lib/etherlite/utils.rb +63 -0
  49. data/lib/etherlite/version.rb +3 -0
  50. data/lib/generators/etherlite/init_generator.rb +10 -0
  51. data/lib/generators/etherlite/templates/etherlite.yml +11 -0
  52. metadata +206 -0
@@ -0,0 +1,29 @@
1
+ require "etherlite/railties/configuration_extensions"
2
+ require "etherlite/railties/utils"
3
+
4
+ # Add rails specifig related configuration parameters
5
+ class Etherlite::Configuration
6
+ include Etherlite::Railties::ConfigurationExtensions
7
+ end
8
+
9
+ module Etherlite
10
+ class Railtie < Rails::Railtie
11
+ initializer "etherlite.configure" do
12
+ if File.exists? "#{Rails.application.paths['config'].existent.first}/etherlite.yml"
13
+ Etherlite.configure Rails.application.config_for(:etherlite)
14
+ end
15
+
16
+ Etherlite.config.logger = Rails.logger
17
+ end
18
+
19
+ initializer "etherlite.load_available_contracts", after: "etherlite.configure" do
20
+ Etherlite::Railties::Utils.load_contracts(Rails.root.join(Etherlite.config.contracts_path))
21
+ end
22
+
23
+ rake_tasks do
24
+ # Nothing for now
25
+ end
26
+
27
+ # IDEA: use config.to_prepare to reload contracts on every request.
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ module Etherlite::Railties
2
+ module ConfigurationExtensions
3
+ def self.included(_klass)
4
+ _klass::DEFAULTS[:contracts_path] = 'contracts'
5
+ end
6
+
7
+ attr_accessor :contracts_path
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Etherlite::Railties
2
+ module Utils
3
+ def self.load_contracts(_path, prefix: 'Contract')
4
+ Dir.glob(_path.join('**/*.json')).map do |fullpath|
5
+ path = Pathname.new fullpath
6
+ path = path.relative_path_from _path
7
+ path = path.dirname.join(path.basename(path.extname)).to_s
8
+
9
+ Object.const_set(path.camelize + prefix, Etherlite::Abi.load_contract_at(fullpath))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ module Etherlite::Types
2
+ class Address < Base
3
+ def signature
4
+ "address" # not sure about this
5
+ end
6
+
7
+ def size
8
+ 32
9
+ end
10
+
11
+ def encode(_value)
12
+ _value = Etherlite::Utils.normalize_address_param _value
13
+ _value.to_raw_hex.rjust(64, '0')
14
+ end
15
+
16
+ def decode(_connection, _value)
17
+ Etherlite::Address.new _connection, _value[24..-1].downcase
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ module Etherlite::Types
2
+ class ArrayBase < Base
3
+ attr_reader :subtype
4
+
5
+ def initialize(_subtype)
6
+ raise ArgumentError, 'An array can not contain a dynamic type' if _subtype.dynamic?
7
+ @subtype = _subtype
8
+ end
9
+
10
+ private
11
+
12
+ def encode_values(_values)
13
+ if @subtype.dynamic?
14
+ encode_dynamic _values
15
+ else
16
+ _values.map { |i| @subtype.encode(i) }.join
17
+ end
18
+ end
19
+
20
+ def encode_dynamic(_values)
21
+ offset = 32 * @size # initial header offset
22
+ header = []
23
+ tail = []
24
+
25
+ _values.each do |item|
26
+ encoded_item = @subtype.encode(item)
27
+
28
+ header << Etherlite::Utils.uint_to_hex(offset)
29
+ tail << encoded_item
30
+ offset += encoded_item.length / 2 # hex string, 2 characters per byte
31
+ end
32
+
33
+ header.join + tail.join
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ module Etherlite::Types
2
+ class ArrayDynamic < ArrayBase
3
+ def signature
4
+ "#{subtype.signature}[]"
5
+ end
6
+
7
+ def encode(_value)
8
+ raise ArgumentError, "expected an array for #{signature}" unless _value.is_a? Array
9
+
10
+ Etherlite::Utils.uint_to_hex(_value.size) + encode_values(_value)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module Etherlite::Types
2
+ class ArrayFixed < ArrayBase
3
+ def initialize(_subtype, _size)
4
+ super _subtype
5
+ @size = _size
6
+ end
7
+
8
+ def signature
9
+ "#{subtype.signature}[#{@size}]"
10
+ end
11
+
12
+ def size
13
+ subtype.size * @size
14
+ end
15
+
16
+ def encode(_value)
17
+ raise ArgumentError, "expected an array for #{signature}" unless _value.is_a? Array
18
+ raise ArgumentError, "expected array of size #{@size}" unless _value.size == @size
19
+
20
+ encode_values _value
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module Etherlite::Types
2
+ class Base
3
+ def signature
4
+ raise NotImplementedError, 'signature must be implemented by base type'
5
+ end
6
+
7
+ def size
8
+ nil
9
+ end
10
+
11
+ def fixed?
12
+ !size.nil?
13
+ end
14
+
15
+ def dynamic?
16
+ size.nil?
17
+ end
18
+
19
+ def encode(_value)
20
+ raise NotImplementedError, 'encode must be implemented by base type'
21
+ end
22
+
23
+ def decode(_connection, _value)
24
+ '0x' + _value
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module Etherlite::Types
2
+ class Bool < Base
3
+ TRUE = '0000000000000000000000000000000000000000000000000000000000000001'.freeze # 32 bytes
4
+ FALSE = '0000000000000000000000000000000000000000000000000000000000000000'.freeze
5
+
6
+ def signature
7
+ "bool"
8
+ end
9
+
10
+ def size
11
+ 32
12
+ end
13
+
14
+ def encode(_value)
15
+ unless _value.is_a?(TrueClass) || _value.is_a?(FalseClass)
16
+ raise ArgumentError, "value must be a boolean for #{signature}"
17
+ end
18
+
19
+ _value ? TRUE : FALSE
20
+ end
21
+
22
+ def decode(_connection, _value)
23
+ _value.hex > 0
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ module Etherlite::Types
2
+ class ByteString < Base
3
+ def signature
4
+ "bytes"
5
+ end
6
+
7
+ def encode(_value)
8
+ raise ArgumentError, "invalid argument type for 'bytes'" unless _value.is_a? ::String
9
+
10
+ bytes_as_hex = _value.unpack('H*').first
11
+ bytes = bytes_as_hex.length / 2
12
+ padded_size = (bytes.to_f / 32).ceil * 32
13
+
14
+ Etherlite::Utils.uint_to_hex(bytes) + bytes_as_hex.ljust(padded_size * 2, '0')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module Etherlite::Types
2
+ class Bytes < Base
3
+ def initialize(_size)
4
+ raise ArgumentError, "invalid byte size #{_size}" unless 0 < _size && _size <= 32
5
+ @size = _size
6
+ end
7
+
8
+ def signature
9
+ "bytes#{@size}"
10
+ end
11
+
12
+ def size
13
+ 32
14
+ end
15
+
16
+ def encode(_value)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ module Etherlite::Types
2
+ class Fixed < Base
3
+ def initialize(_signed, _size_m, _size_n)
4
+ unless 0 < (_size_m + _size_n) && (_size_m + _size_n) <= 256 &&
5
+ _size_m % 8 == 0 && _size_n % 8 == 0
6
+ raise ArgumentError, "invalid fixed size #{_size_m}x#{_size_n}"
7
+ end
8
+
9
+ @signed = _signed
10
+ @size_m = _size_m
11
+ @size_n = _size_n
12
+ end
13
+
14
+ def size
15
+ 32
16
+ end
17
+
18
+ def signature
19
+ "#{@signed ? 'fixed' : 'ufixed'}#{@size_m}x#{@size_n}"
20
+ end
21
+
22
+ def encode(_value)
23
+ raise ArgumentError, "expected a number for #{signature}" unless _value.is_a? Numeric
24
+ raise ArgumentError, "expected a positive number for #{signature}" if !@signed && _value < 0
25
+
26
+ norm_value = (_value * (2**@size_n)).floor
27
+ raise ArgumentError, "value out of bounds #{_value}" if norm_value.abs > maximum
28
+
29
+ @signed ? Etherlite::Utils.int_to_hex(norm_value) : Etherlite::Utils.uint_to_hex(norm_value)
30
+ end
31
+
32
+ private
33
+
34
+ def maximum
35
+ 2**(@signed ? (@size_m + @size_n) - 1 : (@size_m + @size_n))
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ module Etherlite::Types
2
+ class Integer < Base
3
+ def initialize(_signed, _size)
4
+ unless 0 < _size && _size <= 256 && _size % 8 == 0
5
+ raise ArgumentError, "invalid integer size #{_size}"
6
+ end
7
+
8
+ @signed = _signed
9
+ @size = _size
10
+ end
11
+
12
+ def signature
13
+ "#{@signed ? 'int' : 'uint'}#{@size}"
14
+ end
15
+
16
+ def size
17
+ 32
18
+ end
19
+
20
+ def encode(_value)
21
+ raise ArgumentError, "expected a number for #{signature}" unless _value.is_a? ::Integer
22
+ raise ArgumentError, "expected a positive number for #{signature}" if !@signed && _value < 0
23
+ raise ArgumentError, "value out of bounds #{_value}" if _value.abs > maximum
24
+
25
+ @signed ? Etherlite::Utils.int_to_hex(_value) : Etherlite::Utils.uint_to_hex(_value)
26
+ end
27
+
28
+ def decode(_connection, _value)
29
+ @signed ? Etherlite::Utils.hex_to_int(_value) : Etherlite::Utils.hex_to_uint(_value)
30
+ end
31
+
32
+ private
33
+
34
+ def maximum
35
+ 2**(@signed ? @size - 1 : @size)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,10 @@
1
+ module Etherlite::Types
2
+ class String < Base
3
+ def signature
4
+ "string"
5
+ end
6
+
7
+ def encode(_value)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,63 @@
1
+ require "etherlite/commands/utils/validate_address"
2
+
3
+ module Etherlite
4
+ module Utils
5
+ extend self
6
+
7
+ def sha3(_data)
8
+ Digest::SHA3.hexdigest(_data, 256)
9
+ end
10
+
11
+ def uint_to_hex(_value, bytes: 32)
12
+ _value.to_s(16).rjust(bytes * 2, '0')
13
+ end
14
+
15
+ def int_to_hex(_value, bytes: 32)
16
+ if _value < 0
17
+ # 2's complement for negative values
18
+ (_value & ((1 << bytes * 8) - 1)).to_s(16)
19
+ else
20
+ uint_to_hex(_value, bytes: bytes)
21
+ end
22
+ end
23
+
24
+ def hex_to_uint(_hex_value)
25
+ _hex_value.hex
26
+ end
27
+
28
+ def hex_to_int(_hex_value)
29
+ # TODO.
30
+ end
31
+
32
+ def valid_address?(_address)
33
+ ValidateAddress.for(address: _address)
34
+ end
35
+
36
+ def normalize_address(_value)
37
+ _value.gsub(/^0x/, '').downcase
38
+ end
39
+
40
+ def normalize_address_param(_value)
41
+ if _value.respond_to? :address
42
+ _value.address
43
+ else
44
+ _value = _value.to_s
45
+ raise ArgumentError, 'invalid address' unless valid_address? _value
46
+ normalize_address _value
47
+ end
48
+ end
49
+
50
+ def encode_address_param(_value)
51
+ '0x' + normalize_address_param(_value)
52
+ end
53
+
54
+ def encode_block_param(_value)
55
+ return _value.to_s if ['pending', 'earliest', 'latest'].include?(_value.to_s)
56
+ '0x' + _value.to_s(16)
57
+ end
58
+
59
+ def encode_quantity_param(_value)
60
+ '0x' + _value.to_s(16)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Etherlite
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,10 @@
1
+ module Etherlite
2
+ class InitGenerator < Rails::Generators::Base
3
+ source_root File.expand_path("../templates", __FILE__)
4
+
5
+ desc "Initializes the app to work with etherlite"
6
+ def create_index
7
+ template("etherlite.yml", "config/etherlite.yml")
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ defaults:
2
+ contract_path: 'contracts'
3
+
4
+ development: &defaults
5
+ url: 'http://127.0.0.1:8545'
6
+
7
+ test: &defaults
8
+ url: 'http://127.0.0.1:8545'
9
+
10
+ production: &defaults
11
+ url: 'http://127.0.0.1:8545'
metadata ADDED
@@ -0,0 +1,206 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: etherlite
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ignacio Baixas
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-06-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: digest-sha3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: power-types
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
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: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.14'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.14'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '4.7'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '4.7'
125
+ description: ''
126
+ email:
127
+ - ignacio@surbtc.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".rspec"
134
+ - ".travis.yml"
135
+ - CODE_OF_CONDUCT.md
136
+ - Gemfile
137
+ - Guardfile
138
+ - LICENSE.txt
139
+ - README.md
140
+ - Rakefile
141
+ - bin/console
142
+ - bin/setup
143
+ - etherlite.gemspec
144
+ - lib/etherlite.rb
145
+ - lib/etherlite/abi.rb
146
+ - lib/etherlite/account.rb
147
+ - lib/etherlite/address.rb
148
+ - lib/etherlite/api/address.rb
149
+ - lib/etherlite/api/node.rb
150
+ - lib/etherlite/client.rb
151
+ - lib/etherlite/commands/abi/load_contract.rb
152
+ - lib/etherlite/commands/abi/load_function.rb
153
+ - lib/etherlite/commands/abi/load_type.rb
154
+ - lib/etherlite/commands/base.rb
155
+ - lib/etherlite/commands/contract/event_base/decode_log_inputs.rb
156
+ - lib/etherlite/commands/contract/function/encode_arguments.rb
157
+ - lib/etherlite/commands/utils/validate_address.rb
158
+ - lib/etherlite/configuration.rb
159
+ - lib/etherlite/connection.rb
160
+ - lib/etherlite/contract/base.rb
161
+ - lib/etherlite/contract/event_base.rb
162
+ - lib/etherlite/contract/event_input.rb
163
+ - lib/etherlite/contract/function.rb
164
+ - lib/etherlite/railtie.rb
165
+ - lib/etherlite/railties/configuration_extensions.rb
166
+ - lib/etherlite/railties/utils.rb
167
+ - lib/etherlite/types/address.rb
168
+ - lib/etherlite/types/array_base.rb
169
+ - lib/etherlite/types/array_dynamic.rb
170
+ - lib/etherlite/types/array_fixed.rb
171
+ - lib/etherlite/types/base.rb
172
+ - lib/etherlite/types/bool.rb
173
+ - lib/etherlite/types/byte_string.rb
174
+ - lib/etherlite/types/bytes.rb
175
+ - lib/etherlite/types/fixed.rb
176
+ - lib/etherlite/types/integer.rb
177
+ - lib/etherlite/types/string.rb
178
+ - lib/etherlite/utils.rb
179
+ - lib/etherlite/version.rb
180
+ - lib/generators/etherlite/init_generator.rb
181
+ - lib/generators/etherlite/templates/etherlite.yml
182
+ homepage: https://github.com/SurBTC/etherlite
183
+ licenses:
184
+ - MIT
185
+ metadata: {}
186
+ post_install_message:
187
+ rdoc_options: []
188
+ require_paths:
189
+ - lib
190
+ required_ruby_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ required_rubygems_version: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ version: '0'
200
+ requirements: []
201
+ rubyforge_project:
202
+ rubygems_version: 2.6.4
203
+ signing_key:
204
+ specification_version: 4
205
+ summary: Ethereum integration for ruby on rails
206
+ test_files: []