etheruby 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 200899891a140cea002a7e7d9c1ac9916908275b
4
- data.tar.gz: d01b91005637a2ee3543a0d1206a8a59bd265f93
3
+ metadata.gz: 0c566325afa370e6f3d4dc52964b205b26a53da7
4
+ data.tar.gz: 10cd9eac53229fe3a293fe0cefc879abf9d2cc3f
5
5
  SHA512:
6
- metadata.gz: 76545aa6b9a4f8bf92e18b35556a2b4361607e5628760d940c4badf57e9a564dde5785fd6b3694c409a4800bf2df4e0f5129abbf1f3f1b78d36334015cd3386f
7
- data.tar.gz: d7f1fcaf796b041096484d2ba695a5c9acbd4ee1c92cc22dea0822b3664dd807e2035b372751e2d8d968f13a483f1a2933578f5241fdc8ac8bc95c809a96f045
6
+ metadata.gz: 6dc714bdcc04e5778b508d809e5e29fb230c4a1640f3e377c55d123a12d9929eb879f6d73175274816b7491a0943c2e96a0b60216ce240b2630e3038ff5553e8
7
+ data.tar.gz: c3cae2decb6fb2c2f8e79c3d27ed2dcbf3cf2c2ece666382445892cba8f226a4946e1f598a4f2803dd358b0158f35fab32c9cf24b3c1270a83c2ab8a97ea708b
@@ -1,9 +1,12 @@
1
+ require 'bigdecimal'
2
+ require_relative 'type_matchers'
3
+
1
4
  module Etheruby
2
5
 
3
6
  class IncorrectTypeError < StandardError; end
4
7
  class ArgumentsCountError < StandardError; end
8
+ class InvalidFormatForDataError < StandardError; end
5
9
 
6
- # https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
7
10
  class ArgumentsGenerator
8
11
 
9
12
  attr_reader :params, :args
@@ -13,51 +16,33 @@ module Etheruby
13
16
  @args = args
14
17
  end
15
18
 
16
- def is_sized_type(param)
17
- param.to_s.match /^([a-z]+)(\d+)$/
18
- end
19
+ def treat_variable(param, arg)
20
+ if match = TypeMatchers.is_sized_type(param)
21
+ # Parameter is a sized type, e.g. uint256, byte32 ...
22
+ send("#{match[1]}_encode".to_sym, match[2].to_i, arg)
19
23
 
20
- def is_static_array_type(param)
21
- param.to_s.match(/^([a-z]+)\[(\d+)\]$/)
22
- end
24
+ elsif match = TypeMatchers.is_dualsized_type(param)
25
+ # Parameter is a dual sized array type, e.g. fixed16x16
26
+ send("#{match[1]}_encode".to_sym, match[2].to_i, match[3].to_i, arg)
27
+
28
+ elsif match = TypeMatchers.is_static_array_type(param)
29
+ # Parameter is a staticly sized array type, e.g. uint256[24]
30
+ static_array_encode(match[1], match[2].to_i, arg)
31
+
32
+ elsif match = TypeMatchers.is_dynamic_array_type(param)
33
+ # Parameter is a dynamicaly sized array type, e.g. uint256[]
34
+ dynamic_array_encode(match[1], arg)
23
35
 
24
- def is_dynamic_array_type(param)
25
- param.to_s.match(/^([a-z]+)\[\]$/)
36
+ else
37
+ # Parameter is a single-word type : string, bytes, address etc...
38
+ send("#{param}_encode".to_sym, arg)
39
+
40
+ end
26
41
  end
27
42
 
28
43
  def to_s
29
44
  raise ArgumentsCountError.new unless params.count == args.count
30
- arguments = ""
31
- # For each parameter of the method called, we
32
- # match the corresponding type to encode and we send the
33
- # parameter given to this encoder
34
- (0..params.count-1).each do |i|
35
- param, arg = params[i], args[i]
36
- if match = is_sized_type(param)
37
- # Parameter is a sized type, e.g. uint256, byte32 ...
38
- method_name = "#{match[1]}_encode".to_sym
39
- if respond_to?(method_name)
40
- arguments += send(method_name, match[2].to_i, arg)
41
- else
42
- raise IncorrectTypeError.new("Type #{param} cannot be encoded")
43
- end
44
- elsif match = is_static_array_type(param)
45
- # Parameter is a staticly sized array type, e.g. uint256[24]
46
- arguments += static_array(match[1], match[2].to_i, arg)
47
- elsif match = is_dynamic_array_type(param)
48
- # Parameter is a dynamicaly sized array type, e.g. uint256[]
49
- arguments += dynamic_array(match[1], arg)
50
- else
51
- # Parameter is a single-word type : string, bytes, address etc...
52
- method_name = "#{param}_encode".to_sym
53
- if respond_to?(method_name)
54
- arguments += send(method_name, arg)
55
- else
56
- raise IncorrectTypeError.new("Type #{param} cannot be encoded")
57
- end
58
- end
59
- end
60
- arguments
45
+ (0..params.count-1).map { |i| treat_variable(params[i], args[i]) }.join
61
46
  end
62
47
 
63
48
  ##
@@ -74,37 +59,60 @@ module Etheruby
74
59
  ##
75
60
  # uint<X> encoding
76
61
  def uint_encode(size, arg)
77
- arg.to_s(16).rjust(size / 4,'0')
62
+ raise InvalidFormatForDataError.new("unsigned integer #{arg} < 0") if arg < 0
63
+ int_encode(size, arg)
64
+ end
65
+
66
+ ##
67
+ # ufixed<X> encoding
68
+ def ufixed_encode(size_i, size_d, arg)
69
+ raise InvalidFormatForDataError.new("unsigned fixed #{arg} < 0") if arg < 0
70
+ fixed_encode(size_i, size_d, arg)
78
71
  end
79
72
 
80
73
  ##
81
74
  # fixed<X> encoding
82
- def fixed_encode(size, arg)
83
- #Todo
75
+ def fixed_encode(size_i, size_d, arg)
76
+ raise InvalidFormatForDataError.new("Please use BigDecimal !") unless arg.is_a? BigDecimal
77
+ if arg >= 0
78
+ int_part, dec_part = arg.to_i, arg - arg.to_i
79
+ else
80
+ int_part, dec_part = arg.to_i, (arg + arg.to_i.abs).abs
81
+ end
82
+ int_encode(size_i, int_part) + \
83
+ decimal_representation(size_d, dec_part)
84
84
  end
85
85
 
86
86
  ##
87
- # ufixed<X> encoding
88
- def ufixed_encode(size, arg)
89
- #Todo
87
+ # Represent the decimal part in hexadimal according to the precision
88
+ def decimal_representation(precision, value)
89
+ (0..precision-1).map {
90
+ int_part, value = (value*2).to_i, (value*2) - (value*2).to_i
91
+ int_part
92
+ }.each_slice(8).map { |slice|
93
+ slice.join.to_i(2).to_s(16).rjust(2,'0')
94
+ }.join
90
95
  end
91
96
 
92
97
  ##
93
98
  # Encode a static array
94
- def static_array(type, size, arg)
95
- #Todo
99
+ def static_array_encode(type, size, arg)
100
+ raise InvalidFormatForDataError.new(
101
+ "Array have #{arg.count} items for #{size} sized variable"
102
+ ) unless arg.count == size
103
+ arg.map { |item| treat_variable(type, item) }.join
96
104
  end
97
105
 
98
106
  ##
99
107
  # Creates a dynamic array
100
- def dynamic_array(type, arg)
101
- #Todo
108
+ def dynamic_array_encode(type, arg)
109
+ uint_encode(256, arg.count) + static_array_encode(type, arg.count, arg)
102
110
  end
103
111
 
104
112
  ##
105
113
  # byte<X> encodeing
106
114
  def byte_encode(size, arg)
107
- arg.map{ |b| b.to_s(16) }.join.rjust(size,'0')
115
+ arg.map{ |b| b.to_s(16).rjust(2,'0') }.join.rjust(size,'0')
108
116
  end
109
117
 
110
118
  ##
@@ -122,7 +130,7 @@ module Etheruby
122
130
  ##
123
131
  # bytes (dynamic size) encoding
124
132
  def bytes_encode(arg)
125
- uint_encode(256, arg.count) + arg.map{ |b| b.to_s(16) }.join
133
+ uint_encode(256, arg.count) + arg.map{ |b| b.to_s(16).rjust(2,'0') }.join
126
134
  end
127
135
 
128
136
  ##
@@ -20,7 +20,7 @@ module Etheruby
20
20
  @sym = sym
21
21
  end
22
22
  def method_missing(sym, *data)
23
- body = { 'id' => 'jsonrpc', 'method' => "#{@sym}_#{sym}", 'params' => data }
23
+ body = { 'id' => '1', 'method' => "#{@sym}_#{sym}", 'params' => data }
24
24
  text_response = http_post_request(::MultiJson.dump(body))
25
25
  ::MultiJson.load(text_response)
26
26
  end
@@ -0,0 +1,110 @@
1
+ require_relative 'type_matchers'
2
+
3
+ module Etheruby
4
+
5
+ class ResponseParser
6
+
7
+ def initialize(_returns, _response)
8
+ @returns = _returns
9
+ @response = _response
10
+ end
11
+
12
+ def treat_variable(param)
13
+ if match = TypeMatchers.is_sized_type(param)
14
+ # Parameter is a sized type, e.g. uint256, byte32 ...
15
+ send("#{match[1]}_decode".to_sym, match[2].to_i)
16
+
17
+ elsif match = TypeMatchers.is_dualsized_type(param)
18
+ # Parameter is a dual sized array type, e.g. fixed16x16
19
+ send("#{match[1]}_decode".to_sym, match[2].to_i, match[3].to_i)
20
+
21
+ elsif match = TypeMatchers.is_static_array_type(param)
22
+ # Parameter is a staticly sized array type, e.g. uint256[24]
23
+ static_array_decode(match[1], match[2].to_i)
24
+
25
+ elsif match = TypeMatchers.is_dynamic_array_type(param)
26
+ # Parameter is a dynamicaly sized array type, e.g. uint256[]
27
+ dynamic_array_decode(match[1])
28
+
29
+ else
30
+ # Parameter is a single-word type : string, bytes, address etc...
31
+ send("#{param}_decode".to_sym)
32
+
33
+ end
34
+ end
35
+
36
+ def parse
37
+ if @returns.count == 1
38
+ treat_variable(@returns[0])
39
+ else
40
+ @returns.map { |type| treat_variable(type) }
41
+ end
42
+ end
43
+
44
+ # Each decode method will receive in parameters the response string remaining
45
+ # to parse. It will extract the type of the response considering it as the
46
+ # first thing in the string and returns the string without it. Doing this,
47
+ # method calls will be chainable easily.
48
+
49
+ ##
50
+ # int<X> decoding
51
+ def int_decode(size)
52
+ end
53
+
54
+ ##
55
+ # uint<X> decoding
56
+ def uint_decode(size)
57
+ v, @response = @response[0..(size/4)].to_i(16),
58
+ @response[(size/4)..@response.length]
59
+ v
60
+ end
61
+
62
+ ##
63
+ # ufixed<X> decoding
64
+ def ufixed_decode(size_i, size_d)
65
+ end
66
+
67
+ ##
68
+ # fixed<X> decoding
69
+ def fixed_decode(size_i, size_d)
70
+ end
71
+
72
+ ##
73
+ # Decodes a static array
74
+ def static_array_decode(type, size)
75
+ end
76
+
77
+ ##
78
+ # Decodes a dynamic array
79
+ def dynamic_array_decode(type)
80
+ end
81
+
82
+ ##
83
+ # byte<X> decoding
84
+ def byte_decode(size)
85
+ end
86
+
87
+ ##
88
+ # address<X> decoding
89
+ def address_decode
90
+ end
91
+
92
+ ##
93
+ # string<x> decoding (as bytes)
94
+ def string_decode
95
+ end
96
+
97
+ ##
98
+ # bytes (dynamic size) decoding
99
+ def bytes_decode
100
+ end
101
+
102
+ ##
103
+ # boolean decoding (as uint8)
104
+ def bool_decode
105
+ uint_decode(8) == 1
106
+ end
107
+
108
+ end
109
+
110
+ end
@@ -0,0 +1,25 @@
1
+ module Etheruby
2
+
3
+ module TypeMatchers
4
+
5
+ def is_sized_type(param)
6
+ param.to_s.match /^([a-z]+)(\d+)$/
7
+ end
8
+
9
+ def is_dualsized_type(param)
10
+ param.to_s.match /^(.+)(\d+)x(\d+)$/
11
+ end
12
+
13
+ def is_static_array_type(param)
14
+ param.to_s.match(/^(.+)\[(\d+)\]$/)
15
+ end
16
+
17
+ def is_dynamic_array_type(param)
18
+ param.to_s.match(/^(.+)\[\]$/)
19
+ end
20
+
21
+ module_function :is_sized_type, :is_dualsized_type,
22
+ :is_static_array_type, :is_dynamic_array_type
23
+ end
24
+
25
+ end
data/lib/etheruby.rb CHANGED
@@ -3,6 +3,7 @@ require 'logger'
3
3
  require_relative 'etheruby/client'
4
4
  require_relative 'etheruby/contract_method_dsl'
5
5
  require_relative 'etheruby/arguments_generator'
6
+ require_relative 'etheruby/response_parser'
6
7
 
7
8
  module Etheruby
8
9
  class NoContractMethodError < StandardError; end
@@ -52,7 +53,11 @@ module Etheruby
52
53
  else
53
54
  @@logger.debug("Response from API for #{method_info[:name]} : #{response.inspect}")
54
55
  end
55
- response['result']
56
+ if method_info.has_key? :returns
57
+ ResponseParser.new(method_info[:returns], response['result']).parse
58
+ else
59
+ response['result']
60
+ end
56
61
  end
57
62
 
58
63
  def self.address
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: etheruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jérémy SEBAN
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-16 00:00:00.000000000 Z
11
+ date: 2017-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: digest-sha3
@@ -80,7 +80,8 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.5'
83
- description: Describe ethereum smart-contract and execute them with ease.
83
+ description: Etheruby is a library including a client for the JSON-RPC API and a Object-Contract
84
+ Mapper to interact with smart-contracts.
84
85
  email: jeremy@seban.eu
85
86
  executables: []
86
87
  extensions: []
@@ -90,6 +91,8 @@ files:
90
91
  - lib/etheruby/arguments_generator.rb
91
92
  - lib/etheruby/client.rb
92
93
  - lib/etheruby/contract_method_dsl.rb
94
+ - lib/etheruby/response_parser.rb
95
+ - lib/etheruby/type_matchers.rb
93
96
  homepage: https://github.com/MechanicalSloth/etheruby
94
97
  licenses:
95
98
  - MIT